package com.zcloud.personnel.positioning.command;

import com.alibaba.cola.exception.BizException;
import com.zcloud.personnel.positioning.command.query.TerminalAppQueryExe;
import com.zcloud.personnel.positioning.domain.model.TerminalE;
import com.zcloud.personnel.positioning.dto.TerminalAppUpdateCmd;
import com.zcloud.personnel.positioning.dto.clientobject.TerminalAppCO;
import com.zcloud.personnel.positioning.persistence.dataobject.CorpInfoSnapshotDO;
import com.zcloud.personnel.positioning.persistence.dataobject.TerminalPersonSnapshotDO;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;

@Component
@AllArgsConstructor
public class TerminalAppUpdateExe {
    private final TerminalBindingService terminalBindingService;
    private final FindsPendingSyncService findsPendingSyncService;
    private final TerminalAppQueryExe terminalAppQueryExe;

    @Transactional(rollbackFor = Exception.class)
    public TerminalAppCO execute(TerminalAppUpdateCmd cmd) {
        if (cmd == null || cmd.getId() == null) throw new BizException("APP terminal id is required");
        TerminalE terminal = terminalBindingService.findTerminalById(cmd.getId());
        if (terminal == null || !"APP".equalsIgnoreCase(terminal.getDeviceType())) {
            throw new BizException("APP terminal does not exist");
        }
        String oldTerminalNo = terminal.getTerminalNo();
        String oldAppAccount = terminal.getAppAccount();
        String newAppAccount = firstText(cmd.getAppAccount(), oldAppAccount);
        String newTerminalNo = resolveTerminalNo(cmd.getTerminalNo(), firstText(newAppAccount, oldTerminalNo));
        if (!newTerminalNo.equals(oldTerminalNo)) {
            TerminalE duplicate = terminalBindingService.findTerminalByNo(newTerminalNo);
            if (duplicate != null && !duplicate.getId().equals(terminal.getId())) {
                throw new BizException("FindS terminal no already exists");
            }
        }
        if (StringUtils.hasText(newAppAccount) && !newAppAccount.equals(oldAppAccount)) {
            TerminalE duplicate = terminalBindingService.findAppByAccount(newAppAccount);
            if (duplicate != null && !duplicate.getId().equals(terminal.getId())) {
                throw new BizException("APP account already exists");
            }
        }
        CorpInfoSnapshotDO corpInfo = terminalBindingService.resolveCorpInfo(cmd.getCorpinfoId(),
                cmd.getCorpinfoName(), cmd.getOrgCode(), cmd.getOrgName());
        applyUpdate(cmd, terminal, corpInfo, newTerminalNo, newAppAccount);
        terminal.setSyncStatus(FindsPendingSyncService.STATUS_WAIT);
        terminal.setSyncToken(FindsSyncToken.next());
        terminalBindingService.updateTerminal(terminal);
        if (!oldTerminalNo.equals(terminal.getTerminalNo())) {
            terminalBindingService.moveActiveBindingTerminalNo(oldTerminalNo, terminal);
        }
        if (Boolean.TRUE.equals(cmd.getClearBind())) {
            terminalBindingService.unbindActiveBinding(terminal, true, LocalDateTime.now());
        } else {
            TerminalPersonSnapshotDO person = terminalBindingService.resolvePerson(cmd.getBindIdCardNo(),
                    cmd.getStaffNo(), cmd.getStaffName());
            if (person != null) terminalBindingService.upsertActiveBinding(terminal, person, true, LocalDateTime.now());
        }
        findsPendingSyncService.scheduleTerminal(terminal.getId());
        return terminalAppQueryExe.queryAppById(terminal.getId());
    }

    private void applyUpdate(TerminalAppUpdateCmd cmd, TerminalE terminal, CorpInfoSnapshotDO corpInfo,
                             String terminalNo, String appAccount) {
        terminal.setTerminalNo(terminalNo);
        terminal.setAppAccount(appAccount);
        if (cmd.getTerminalName() != null) terminal.setTerminalName(cmd.getTerminalName());
        if (cmd.getCorpinfoId() != null || corpInfo != null) {
            terminal.setCorpinfoId(corpInfo == null ? cmd.getCorpinfoId() : corpInfo.getCorpinfoId());
        }
        if (cmd.getCorpinfoName() != null || corpInfo != null) {
            terminal.setCorpinfoName(firstText(cmd.getCorpinfoName(), corpInfo == null ? null : corpInfo.getCorpName()));
        }
        if (cmd.getOrgCode() != null || corpInfo != null) {
            terminal.setOrgCode(firstText(cmd.getOrgCode(), corpInfo == null ? null : corpInfo.getCreditCode()));
        }
        if (cmd.getOrgName() != null || cmd.getCorpinfoName() != null || corpInfo != null) {
            terminal.setOrgName(firstText(cmd.getOrgName(), cmd.getCorpinfoName(),
                    corpInfo == null ? null : corpInfo.getCorpName()));
        }
        if (cmd.getEnable() != null) terminal.setEnable(cmd.getEnable());
        if (cmd.getRemarks() != null) terminal.setRemarks(cmd.getRemarks());
    }

    private String resolveTerminalNo(String terminalNo, String appAccount) {
        String result = firstText(terminalNo, appAccount);
        if (!StringUtils.hasText(result)) throw new BizException("FindS terminal no is required");
        return result.trim();
    }

    private String firstText(String... values) {
        for (String value : values) if (StringUtils.hasText(value)) return value;
        return null;
    }
}
