package shop.alien.store.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import shop.alien.entity.result.R;
import shop.alien.entity.store.CommonPushTask;
import shop.alien.entity.store.CommonPushTaskStatus;
import shop.alien.entity.store.CommonPushTaskUser;
import shop.alien.mapper.CommonPushTaskMapper;
import shop.alien.mapper.CommonPushTaskUserMapper;
import shop.alien.store.dto.CommonPushTaskUserCallbackDto;
import shop.alien.store.service.CommonPushTaskUserService;

@Slf4j
@Service
@RequiredArgsConstructor
public class CommonPushTaskUserServiceImpl extends ServiceImpl<CommonPushTaskUserMapper, CommonPushTaskUser> implements CommonPushTaskUserService {

    private final CommonPushTaskMapper commonPushTaskMapper;

    @Override
    public R<String> add(CommonPushTaskUser taskUser) {
        log.info("CommonPushTaskUserServiceImpl.add, param={}", taskUser);
        boolean result = this.save(taskUser);
        return result ? R.success("新增成功") : R.fail("新增失败");
    }

    @Override
    public R<String> deleteById(Long id) {
        log.info("CommonPushTaskUserServiceImpl.deleteById, id={}", id);
        boolean result = this.removeById(id);
        return result ? R.success("删除成功") : R.fail("删除失败");
    }

    @Override
    public R<String> update(CommonPushTaskUser taskUser) {
        log.info("CommonPushTaskUserServiceImpl.update, param={}", taskUser);
        if (taskUser.getId() == null) {
            return R.fail("id不能为空");
        }
        boolean result = this.updateById(taskUser);
        return result ? R.success("更新成功") : R.fail("更新失败");
    }

    @Override
    public R<CommonPushTaskUser> getInfoById(Long id) {
        log.info("CommonPushTaskUserServiceImpl.getInfoById, id={}", id);
        return R.data(this.getById(id));
    }

    @Override
    public R<IPage<CommonPushTaskUser>> list(Integer pageNum, Integer pageSize, Long pushTaskId, Long userId, String deviceId) {
        log.info("CommonPushTaskUserServiceImpl.list, pageNum={}, pageSize={}, pushTaskId={}, userId={}, deviceId={}",
                pageNum, pageSize, pushTaskId, userId, deviceId);
        Page<CommonPushTaskUser> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<CommonPushTaskUser> wrapper = new LambdaQueryWrapper<>();
        if (pushTaskId != null) {
            wrapper.eq(CommonPushTaskUser::getPushTaskId, pushTaskId);
        }
        if (userId != null) {
            wrapper.eq(CommonPushTaskUser::getUserId, userId);
        }
        if (StringUtils.isNotBlank(deviceId)) {
            wrapper.eq(CommonPushTaskUser::getDeviceId, deviceId);
        }
        wrapper.orderByDesc(CommonPushTaskUser::getUpdatedTime);
        return R.data(this.page(page, wrapper));
    }

    @Override
    public R<String> callbackFromVendor(String callBackParameter, String channelStatus,
                                        String registrationIds, String eventType) {
        log.info("CommonPushTaskUserServiceImpl.callbackFromVendor, callBackParameter={}, channelStatus={}, registrationIds={}, eventType={}",
                callBackParameter, channelStatus, registrationIds, eventType);
        if (StringUtils.isBlank(callBackParameter)) {
            return R.fail("callBackParameter不能为空");
        }
        CommonPushTaskUserCallbackDto callbackDto = new CommonPushTaskUserCallbackDto();
        try {
            JSONObject paramJson = JSONObject.parseObject(callBackParameter);
            if (paramJson != null) {
                fillCallbackDtoFromParamJson(callbackDto, paramJson);
            }
        } catch (Exception e) {
            log.warn("callBackParameter 非 JSON，按原始字符串处理: {}", callBackParameter);
        }
        if (StringUtils.isNotBlank(registrationIds) && StringUtils.isBlank(callbackDto.getDeviceId())) {
            callbackDto.setDeviceId(extractFirstRegistrationId(registrationIds));
        }
        callbackDto.setChannelStatus(channelStatus);
        if (StringUtils.isBlank(callbackDto.getChannelCode())) {
            callbackDto.setChannelCode("oppo");
        }
        if ("0".equals(channelStatus) || "success".equalsIgnoreCase(channelStatus)
                || "push_arrive".equalsIgnoreCase(eventType)) {
            callbackDto.setEventType("delivered");
        }
        return callback(callbackDto);
    }

    private void fillCallbackDtoFromParamJson(CommonPushTaskUserCallbackDto callbackDto, JSONObject paramJson) {
        callbackDto.setTaskNo(StringUtils.defaultIfBlank(paramJson.getString("taskNo"), paramJson.getString("t")));
        Long pushTaskId = paramJson.getLong("pushTaskId");
        if (pushTaskId == null) {
            pushTaskId = paramJson.getLong("p");
        }
        callbackDto.setPushTaskId(pushTaskId);
        Long userId = paramJson.getLong("userId");
        if (userId == null) {
            userId = paramJson.getLong("u");
        }
        callbackDto.setUserId(userId);
        callbackDto.setDeviceId(StringUtils.defaultIfBlank(paramJson.getString("deviceId"), paramJson.getString("d")));
        callbackDto.setChannelCode(paramJson.getString("channelCode"));
    }

    private String extractFirstRegistrationId(String registrationIds) {
        if (StringUtils.isBlank(registrationIds)) {
            return null;
        }
        String[] parts = registrationIds.split(",");
        for (String part : parts) {
            if (StringUtils.isNotBlank(part)) {
                return part.trim();
            }
        }
        return registrationIds.trim();
    }

    @Override
    public R<String> callback(CommonPushTaskUserCallbackDto callbackDto) {
        log.info("CommonPushTaskUserServiceImpl.callback, param={}", callbackDto);
        if (callbackDto == null) {
            return R.fail("回调参数不能为空");
        }
        normalizeChannelPayload(callbackDto);
        applyEventType(callbackDto);

        if (callbackDto.getStatus() == null && callbackDto.getShowInfo() == null && callbackDto.getUserAdd() == null) {
            return R.fail("至少提供一个状态字段或 eventType");
        }

        CommonPushTaskUser record = findCallbackRecord(callbackDto);
        if (record == null) {
            return R.fail("未找到推送记录");
        }

        LambdaUpdateWrapper<CommonPushTaskUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(CommonPushTaskUser::getId, record.getId());
        boolean hasUpdate = false;
        if (callbackDto.getStatus() != null) {
            updateWrapper.set(CommonPushTaskUser::getStatus, callbackDto.getStatus());
            hasUpdate = true;
        }
        if (callbackDto.getShowInfo() != null) {
            updateWrapper.set(CommonPushTaskUser::getShowInfo, callbackDto.getShowInfo());
            hasUpdate = true;
        }
        if (callbackDto.getUserAdd() != null) {
            updateWrapper.set(CommonPushTaskUser::getUserAdd, callbackDto.getUserAdd());
            hasUpdate = true;
        }
        if (!hasUpdate) {
            return R.fail("无可更新字段");
        }
        boolean result = this.update(updateWrapper);
        if (result && callbackDto.getStatus() != null && callbackDto.getStatus() == 1) {
            updatePushTaskDelivered(record.getPushTaskId());
        }
        return result ? R.success("回调处理成功") : R.fail("回调处理失败");
    }

    private void updatePushTaskDelivered(Long pushTaskId) {
        if (pushTaskId == null) {
            return;
        }
        CommonPushTask task = new CommonPushTask();
        task.setId(pushTaskId);
        task.setStatus(CommonPushTaskStatus.DELIVERED);
        commonPushTaskMapper.updateById(task);
    }

    private CommonPushTaskUser findCallbackRecord(CommonPushTaskUserCallbackDto callbackDto) {
        if (callbackDto.getId() != null) {
            return this.getById(callbackDto.getId());
        }
        Long pushTaskId = callbackDto.getPushTaskId();
        if (pushTaskId == null && StringUtils.isNotBlank(callbackDto.getTaskNo())) {
            CommonPushTask task = commonPushTaskMapper.selectOne(
                    new LambdaQueryWrapper<CommonPushTask>()
                            .eq(CommonPushTask::getTaskNo, callbackDto.getTaskNo().trim())
                            .last("LIMIT 1"));
            if (task != null) {
                pushTaskId = task.getId();
            }
        }
        if (pushTaskId == null) {
            return null;
        }
        LambdaQueryWrapper<CommonPushTaskUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CommonPushTaskUser::getPushTaskId, pushTaskId);
        if (StringUtils.isNotBlank(callbackDto.getDeviceId())) {
            wrapper.eq(CommonPushTaskUser::getDeviceId, callbackDto.getDeviceId().trim());
        } else if (callbackDto.getUserId() != null) {
            wrapper.eq(CommonPushTaskUser::getUserId, callbackDto.getUserId());
        } else {
            return null;
        }
        wrapper.orderByDesc(CommonPushTaskUser::getCreatedTime);
        wrapper.last("LIMIT 1");
        return this.getOne(wrapper);
    }

    private void applyEventType(CommonPushTaskUserCallbackDto callbackDto) {
        if (StringUtils.isBlank(callbackDto.getEventType())) {
            return;
        }
        String eventType = callbackDto.getEventType().trim().toLowerCase();
        switch (eventType) {
            case "sent":
            case "send":
                if (callbackDto.getStatus() == null) {
                    callbackDto.setStatus(0);
                }
                break;
            case "delivered":
            case "delivery":
            case "arrive":
            case "receive":
                if (callbackDto.getStatus() == null) {
                    callbackDto.setStatus(1);
                }
                break;
            case "show":
            case "display":
            case "impression":
                if (callbackDto.getShowInfo() == null) {
                    callbackDto.setShowInfo(1);
                }
                break;
            case "click":
            case "open":
            case "tap":
                if (callbackDto.getShowInfo() == null) {
                    callbackDto.setShowInfo(1);
                }
                if (callbackDto.getUserAdd() == null) {
                    callbackDto.setUserAdd(1);
                }
                break;
            default:
                log.warn("未识别的事件类型: {}", eventType);
        }
    }

    /**
     * 将各渠道原始状态码映射为统一状态字段。
     */
    private void normalizeChannelPayload(CommonPushTaskUserCallbackDto callbackDto) {
        if (StringUtils.isBlank(callbackDto.getChannelCode()) || StringUtils.isBlank(callbackDto.getChannelStatus())) {
            return;
        }
        String channelCode = callbackDto.getChannelCode().trim().toLowerCase();
        String channelStatus = callbackDto.getChannelStatus().trim().toLowerCase();
        switch (channelCode) {
            case "vivo":
            case "xiaomi":
            case "oppo":
            case "samsung":
                if ("0".equals(channelStatus) || "success".equals(channelStatus) || "ok".equals(channelStatus)
                        || "1000".equals(channelStatus)) {
                    if (callbackDto.getStatus() == null) {
                        callbackDto.setStatus(1);
                    }
                }
                break;
            case "huawei":
            case "honor":
                if ("delivered".equals(channelStatus) || "success".equals(channelStatus)) {
                    if (callbackDto.getStatus() == null) {
                        callbackDto.setStatus(1);
                    }
                }
                break;
            case "apns":
                if ("delivered".equals(channelStatus) || "200".equals(channelStatus)) {
                    if (callbackDto.getStatus() == null) {
                        callbackDto.setStatus(1);
                    }
                }
                break;
            default:
                break;
        }
    }
}
