package com.bcxin.backend.domain.repositories.impls;

import com.bcxin.backend.core.exceptions.SaasBadException;
import com.bcxin.backend.core.utils.ExceptionUtils;
import com.bcxin.backend.domain.models.DomainSuperviseDTO;
import com.bcxin.backend.domain.models.SuperviseDTO;
import com.bcxin.backend.domain.repositories.DomainSuperviseRepository;
import com.bcxin.backend.domain.repositories.dtos.RegionDomainDTO;
import com.bcxin.backend.domain.repositories.dtos.RegionSystemDomainGroupDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.*;
import java.util.stream.Collectors;

@Component
public class DomainSuperviseRepositoryImpl implements DomainSuperviseRepository {
    private final Logger logger = LoggerFactory.getLogger(DomainSuperviseRepositoryImpl.class);
    private final String QUERY_SQL_STATEMENT = "select '[[domainId]]' AS DOMAINID, rs.item_regionId,rs.item_systemAdmin,rs.item_systemURL,rs.item_systemURLNw,rs.item_callbackUrl,rs.item_targetServiceUrl from  [[DS_ORGANIZATIONAUTH]].tlk_RegionSystem rs  inner JOIN  [[DS_ORGANIZATIONAUTH]].tlk_DepartmentLevel dl on rs.ITEM_REGIONId=dl.ITEM_REGIONId and  dl.id in (select item_registerPoliceAddressID from tlk_SetSupervise WHERE domainid='[[domainId]]') GROUP BY DOMAINID, ITEM_REGIONId,item_systemAdmin,item_systemURL";
    private final DataSource dataSource;
    private final String organizationDbName;
    private final SuperviseDTO defaultSupervise;
    public DomainSuperviseRepositoryImpl(
            @Qualifier("baoanDataSource")
                    DataSource dataSource,
            @Value("${db.organization.name}") String organizationDbName,
            SuperviseDTO defaultSupervise) {
        this.dataSource = dataSource;
        this.organizationDbName = organizationDbName;
        this.defaultSupervise = defaultSupervise;
    }

    @Override
    public Collection<DomainSuperviseDTO> getAll(Collection<String> domainIds) {
        List<DomainSuperviseDTO> result = new ArrayList<>();
        try {
            int skip = 0;
            int page = 100;
            Collection<String> pagedDomainIds = null;
            do {
                pagedDomainIds = domainIds.stream().skip(skip * page).limit(page).collect(Collectors.toList());
                Collection<DomainSuperviseDTO> newDomainSupervises =
                        getAllPagedSupervises(pagedDomainIds).stream().filter(ii -> !result.stream()
                                .anyMatch(ix -> ix.getIdentityValue().equalsIgnoreCase(ii.getIdentityValue())))
                                .collect(Collectors.toList());

                result.addAll(newDomainSupervises);

                skip++;
            }
            while (pagedDomainIds != null && pagedDomainIds.size() > 0);
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new SaasBadException("监管机构获取失败!", ex);
        }

        return result;
    }

    @Override
    public Collection<DomainSuperviseDTO> getDomainSuperviseDTOForBaseData() {
        if(defaultSupervise!=null && defaultSupervise.isValid()) {
            return Collections.singleton(DomainSuperviseDTO.create(null, defaultSupervise));
        }

        return getRegionSystemDomainGroups().stream().map(ii -> {
            return DomainSuperviseDTO.create(null, ii.getSuperviseDTO());
        }).collect(Collectors.toList());
    }


    private static boolean toUseDefaultSupervises = false;
    private Collection<DomainSuperviseDTO> getAllPagedSupervises(Collection<String> domainIds) {
        if (domainIds == null || domainIds.isEmpty()) {
            return new ArrayList<>();
        }

        domainIds = domainIds.stream().distinct().collect(Collectors.toList());
        if(toUseDefaultSupervises|| (defaultSupervise!=null && defaultSupervise.isValid())) {
            return getDefaultDomainSupervises(domainIds);
        }

        try {
            Collection<RegionSystemDomainGroupDTO> regionSystemDomainGroupDTOS = getRegionSystemDomainGroups();
            Collection<String> notExistsDomainIds = domainIds.stream().filter(ii ->
                    !regionSystemDomainGroupDTOS.stream().anyMatch(ix -> ix.isExists(ii)))
                    .collect(Collectors.toList());

            Collection<RegionDomainDTO> regionDomainDTOS = getRegionDomains(notExistsDomainIds);
            for (RegionDomainDTO regionDomain : regionDomainDTOS) {
                regionSystemDomainGroupDTOS.stream()
                        .filter(ii -> ii.isRegionMatch(regionDomain.getRegionId()))
                        .forEach(regionSystemDomainGroupDTO -> {
                            regionSystemDomainGroupDTO.addDomainId(regionDomain.getDomainId());
                        });
            }

            return domainIds.stream().flatMap(ii -> {
                return regionSystemDomainGroupDTOS.stream().filter(ix -> ix.isExists(ii))
                        .map(ix -> DomainSuperviseDTO.create(ii, ix.getSuperviseDTO()));
            }).collect(Collectors.toList());
        } catch (Exception ex) {
            if (ex.getClass().getName().equalsIgnoreCase(SaasBadException.class.getName()) &&
                    ex.toString().contains("tlk_regionsystem")) {
                toUseDefaultSupervises = true;
                return getDefaultDomainSupervises(domainIds);
            }

            throw ex;
        }
    }

    private Collection<DomainSuperviseDTO> getDefaultDomainSupervises(Collection<String> domainIds)
    {
        return domainIds.stream().map(ii -> {
            return DomainSuperviseDTO.create(ii, defaultSupervise.clone());

        }).collect(Collectors.toList());
    }

    private static Collection<RegionSystemDomainGroupDTO> cache_regionSystemDomainGroupDTO = new ArrayList<>();
    private Collection<RegionSystemDomainGroupDTO> getRegionSystemDomainGroups() {
        String sql = ("select rs.item_regionId,rs.item_systemAdmin,rs.item_systemURL,rs.item_systemURLNw,rs.item_callbackUrl,rs.item_targetServiceUrl from [[DS_ORGANIZATIONAUTH]].tlk_RegionSystem rs  ")
                .replace("[[DS_ORGANIZATIONAUTH]]", organizationDbName);

        if (cache_regionSystemDomainGroupDTO.size() == 0) {
            try (PreparedStatement statement = dataSource.getConnection().prepareStatement(sql)) {
                ResultSet resultSet = statement.executeQuery();
                while (resultSet.next()) {
                    String regionId = resultSet.getString(1);
                    String systemAdmin = resultSet.getString(2);
                    String systemURL = resultSet.getString(3);
                    String systemURLNw = resultSet.getString(4);
                    String callbackUrl = resultSet.getString(5);
                    String targetServiceUrl = resultSet.getString(6);

                    SuperviseDTO superviseDTO = new SuperviseDTO();
                    superviseDTO.setRegionId(regionId);
                    superviseDTO.setSystemAdmin(systemAdmin);
                    superviseDTO.setSrcApp(systemURL);
                    superviseDTO.setTargetApp(systemURLNw);
                    superviseDTO.setCallbackUrl(callbackUrl);
                    superviseDTO.setTargetServiceUrl(targetServiceUrl);
                    RegionSystemDomainGroupDTO regionSystemDomainGroupDTO = RegionSystemDomainGroupDTO.create(superviseDTO);

                    cache_regionSystemDomainGroupDTO.add(regionSystemDomainGroupDTO);
                }
            } catch (Exception ex) {
                throw new SaasBadException(String.format("获取监管配置信息:%s", ExceptionUtils.getStackMessage(ex)));
            }
        }

        return cache_regionSystemDomainGroupDTO;
    }

    private Collection<RegionDomainDTO> getRegionDomains(Collection<String> domainIds) {
        if(domainIds.size()==0) {
            return Collections.emptyList();
        }

        String notExistsDomainIds = domainIds.stream().map(ii -> String.format("'%s'", ii)).collect(Collectors.joining(","));

        String sql = String.format("select tk.domainid,dl.ITEM_REGIONId from [[DS_ORGANIZATIONAUTH]].tlk_DepartmentLevel dl join tlk_SetSupervise tk on dl.id=tk.item_registerPoliceAddressID where tk.domainid in ([[DOMAINIDS]]) ")
                .replace("[[DS_ORGANIZATIONAUTH]]", organizationDbName)
                .replace("[[DOMAINIDS]]", notExistsDomainIds);

        Collection<RegionDomainDTO> regionDomainDTOS = new ArrayList<>();

        try {
            try (Connection connection = dataSource.getConnection()) {
                try (PreparedStatement statement = connection.prepareStatement(sql)) {
                    ResultSet resultSet = statement.executeQuery();
                    while (resultSet.next()) {
                        String domainId = resultSet.getString(1);
                        String regionId = resultSet.getString(2);
                        regionDomainDTOS.add(RegionDomainDTO.create(domainId, regionId));
                    }
                }
            } catch (Exception ex) {
                logger.error(String.format("获取归属地信息失败:jdbc=%s;username=%s;sql=%s!",
                        dataSource.getConnection().getMetaData().getURL(),
                        dataSource.getConnection().getMetaData().getUserName(),
                        sql));

                ex.printStackTrace();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new SaasBadException("监管机构获取失败!", ex);
        }

        return regionDomainDTOS;
    }
}
