package com.sino.mci.crm.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sino.mci.crm.dto.BindTagsRequest;
import com.sino.mci.crm.dto.CreateIdentityRequest;
import com.sino.mci.crm.dto.CreatePersonRequest;
import com.sino.mci.crm.dto.UpdatePersonRequest;
import com.sino.mci.crm.entity.ChannelIdentity;
import com.sino.mci.crm.entity.Person;
import com.sino.mci.crm.entity.PersonTagBinding;
import com.sino.mci.crm.entity.Tag;
import com.sino.mci.crm.repository.ChannelIdentityMapper;
import com.sino.mci.crm.repository.PersonMapper;
import com.sino.mci.crm.repository.PersonTagBindingMapper;
import com.sino.mci.crm.repository.TagMapper;
import com.sino.mci.exception.BusinessException;
import com.sino.mci.shared.util.JsonUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class PersonService {

    private final PersonMapper personMapper;
    private final ChannelIdentityMapper identityMapper;
    private final PersonTagBindingMapper personTagBindingMapper;
    private final TagMapper tagMapper;

    public List<Person> listPersons(String tenantCode) {
        return personMapper.selectList(
                new LambdaQueryWrapper<Person>()
                        .eq(Person::getTenantCode, tenantCode)
                        .eq(Person::getStatus, 1)
                        .orderByDesc(Person::getId));
    }

    @Transactional
    public Person createPerson(String tenantCode, CreatePersonRequest request) {
        Person person = new Person();
        person.setTenantCode(tenantCode);
        person.setPersonCode(request.getPersonCode());
        person.setPersonName(request.getPersonName());
        person.setPhone(request.getPhone());
        person.setPersonType(request.getPersonType());
        person.setInstitutionId(request.getInstitutionId());
        person.setSupplierId(request.getSupplierId());
        person.setStatus(1);
        personMapper.insert(person);
        return person;
    }

    public Person getPerson(String tenantCode, Long personId) {
        Person person = personMapper.selectById(personId);
        if (person == null || !tenantCode.equals(person.getTenantCode())) {
            throw new BusinessException("联系人不存在");
        }
        return person;
    }

    @Transactional
    public Person updatePerson(String tenantCode, Long personId, UpdatePersonRequest request) {
        Person person = getPerson(tenantCode, personId);
        person.setPersonName(request.getPersonName());
        if (request.getPhone() != null) {
            person.setPhone(request.getPhone());
        }
        if (request.getPersonType() != null) {
            person.setPersonType(request.getPersonType());
        }
        if (request.getStatus() != null) {
            person.setStatus(request.getStatus());
        }
        if (request.getInstitutionId() != null) {
            person.setInstitutionId(request.getInstitutionId());
        }
        if (request.getSupplierId() != null) {
            person.setSupplierId(request.getSupplierId());
        }
        personMapper.updateById(person);
        return person;
    }

    @Transactional
    public void deletePerson(String tenantCode, Long personId) {
        getPerson(tenantCode, personId);
        personMapper.deleteById(personId);
    }

    public List<ChannelIdentity> listIdentities(String tenantCode, Long personId) {
        getPerson(tenantCode, personId);
        return identityMapper.selectList(
                new LambdaQueryWrapper<ChannelIdentity>()
                        .eq(ChannelIdentity::getTenantCode, tenantCode)
                        .eq(ChannelIdentity::getPersonId, personId));
    }

    @Transactional
    public ChannelIdentity createIdentity(String tenantCode, CreateIdentityRequest request) {
        getPerson(tenantCode, request.getPersonId());

        ChannelIdentity existing = identityMapper.selectOne(
                new LambdaQueryWrapper<ChannelIdentity>()
                        .eq(ChannelIdentity::getTenantCode, tenantCode)
                        .eq(ChannelIdentity::getChannelType, request.getChannelType())
                        .eq(ChannelIdentity::getChannelUserId, request.getChannelUserId()));
        if (existing != null) {
            throw new BusinessException("渠道身份已存在: " + request.getChannelUserId());
        }

        ChannelIdentity identity = new ChannelIdentity();
        identity.setTenantCode(tenantCode);
        identity.setPersonId(request.getPersonId());
        identity.setChannelType(request.getChannelType());
        identity.setChannelUserId(request.getChannelUserId());
        identity.setChannelUserName(request.getChannelUserName());
        identity.setSubjectId(request.getSubjectId());
        identity.setStatus(1);
        identity.setExtInfo(JsonUtils.toJson(request.getExtInfo()));
        identityMapper.insert(identity);
        return identity;
    }

    @Transactional
    public void deleteIdentity(String tenantCode, Long personId, Long identityId) {
        getPerson(tenantCode, personId);
        ChannelIdentity identity = identityMapper.selectById(identityId);
        if (identity == null || !tenantCode.equals(identity.getTenantCode())
                || !personId.equals(identity.getPersonId())) {
            throw new BusinessException("渠道身份不存在");
        }
        identityMapper.deleteById(identityId);
    }

    @Transactional
    public void bindTags(String tenantCode, Long personId, BindTagsRequest request) {
        getPerson(tenantCode, personId);
        for (Long tagId : request.getTagIds()) {
            Tag tag = tagMapper.selectById(tagId);
            if (tag == null || !tenantCode.equals(tag.getTenantCode())) {
                throw new BusinessException("标签不存在: " + tagId);
            }
        }

        personTagBindingMapper.delete(
                new LambdaQueryWrapper<PersonTagBinding>()
                        .eq(PersonTagBinding::getPersonId, personId));

        if (!CollectionUtils.isEmpty(request.getTagIds())) {
            List<PersonTagBinding> bindings = request.getTagIds().stream()
                    .distinct()
                    .map(tagId -> {
                        PersonTagBinding binding = new PersonTagBinding();
                        binding.setTenantCode(tenantCode);
                        binding.setTagId(tagId);
                        binding.setPersonId(personId);
                        return binding;
                    })
                    .collect(Collectors.toList());
            for (PersonTagBinding binding : bindings) {
                personTagBindingMapper.insert(binding);
            }
        }
    }
}
