package com.ycwl.basic.service.pc.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.facebody.FaceBodyFactory;
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
import com.ycwl.basic.mapper.ScenicAccountMapper;
import com.ycwl.basic.mapper.ScenicMapper;
import com.ycwl.basic.model.pc.scenic.entity.ScenicAccountEntity;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.pc.scenic.req.ScenicAddOrUpdateReq;
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
import com.ycwl.basic.pay.PayFactory;
import com.ycwl.basic.pay.adapter.IPayAdapter;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.pc.ScenicService;
import com.ycwl.basic.service.task.TaskFaceService;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.exceptions.StorageUnsupportedException;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.SnowFlakeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static com.ycwl.basic.constant.FaceConstant.USER_FACE_DB_NAME;

/**
 * @Author：longbinbin
 * @Date：2024/12/3 15:25
 */
@Slf4j
@Service
public class ScenicServiceImpl implements ScenicService {
    @Autowired
    private ScenicMapper scenicMapper;
    @Autowired
    private ScenicAccountMapper scenicAccountMapper;
    @Autowired
    private TaskFaceService taskFaceService;
    @Autowired
    private ScenicRepository scenicRepository;

    @Override
    public ApiResponse<PageInfo<ScenicRespVO>> pageQuery(ScenicReqQuery scenicReqQuery) {
        PageHelper.startPage(scenicReqQuery.getPageNum(), scenicReqQuery.getPageSize());
        List<ScenicRespVO> list = scenicMapper.list(scenicReqQuery);
        PageInfo<ScenicRespVO> pageInfo = new PageInfo<>(list);
        return ApiResponse.success(pageInfo);
    }

    @Override
    public ApiResponse<List<ScenicRespVO>> list(ScenicReqQuery scenicReqQuery) {
        return ApiResponse.success(scenicMapper.list(scenicReqQuery));
    }

    @Override
    public ApiResponse<ScenicRespVO> getById(Long id) {
        return ApiResponse.success(scenicMapper.getById(id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResponse<Boolean> add(ScenicAddOrUpdateReq scenicAddReq) {
        ScenicAccountEntity scenicAccount = scenicAccountMapper.getByAccount(scenicAddReq.getAccount());
        if (scenicAccount != null) {
            return ApiResponse.fail("账号已存在");
        }
        Long scenicId = SnowFlakeUtil.getLongId();
        scenicAddReq.setId(scenicId);
        int add = scenicMapper.add(scenicAddReq);
        ScenicAccountEntity account = new ScenicAccountEntity();
        account.setId(SnowFlakeUtil.getLongId());
        account.setScenicId(scenicId);
        account.setName(scenicAddReq.getName() + "管理员");
        account.setAccount(scenicAddReq.getAccount());
        account.setPassword(scenicAddReq.getPassword());
        account.setIsSuper(1);
        scenicAccountMapper.add(account);
        if (add > 0) {
            return ApiResponse.success(true);
        } else {
            return ApiResponse.fail("景区添加失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResponse<Boolean> deleteById(Long id) {
        int i = scenicMapper.deleteById(id);
        if (i > 0) {
            scenicAccountMapper.deleteByScenicId(id);
            IFaceBodyAdapter adapter = getScenicFaceBodyAdapter(id);
            (new Thread(() -> {
                adapter.deleteFaceDb(id.toString());
                adapter.deleteFaceDb(USER_FACE_DB_NAME + id);
            })).start();
            scenicMapper.deleteConfigByScenicId(id);
            scenicRepository.clearCache(id);
            scenicFaceBodyAdapterMap.remove(id);
            scenicStorageAdapterMap.remove(id);
            scenicPayAdapterMap.remove(id);
            return ApiResponse.success(true);
        }else {
            return ApiResponse.fail("景区删除失败");
        }
    }

    @Override
    public ApiResponse<Boolean> update(ScenicAddOrUpdateReq scenicUpdateReq) {
        if (StringUtils.isNotBlank(scenicUpdateReq.getAccount()) && StringUtils.isNotBlank(scenicUpdateReq.getPassword())) {
            ScenicAccountEntity scenicAccount = scenicAccountMapper.getByAccount(scenicUpdateReq.getAccount());
            if (scenicAccount != null) {
                if (!scenicAccount.getScenicId().equals(scenicUpdateReq.getId())) {
                    return ApiResponse.fail("账号已存在");
                }
            }
            ScenicAccountEntity account = scenicAccountMapper.getSuperAccountOfScenic(scenicUpdateReq.getId());
            if (account != null) {
                account.setAccount(scenicUpdateReq.getAccount());
                account.setPassword(scenicUpdateReq.getPassword());
                scenicAccountMapper.update(account);
            } else {
                account = new ScenicAccountEntity();
                account.setId(SnowFlakeUtil.getLongId());
                account.setScenicId(scenicUpdateReq.getId());
                account.setName(scenicUpdateReq.getName() + "管理员");
                account.setAccount(scenicUpdateReq.getAccount());
                account.setPassword(scenicUpdateReq.getPassword());
                account.setIsSuper(1);
                scenicAccountMapper.add(account);
            }
        }
        int i = scenicMapper.update(scenicUpdateReq);
        if (i > 0) {
            scenicRepository.clearCache(scenicUpdateReq.getId());
            return ApiResponse.success(true);
        }else {
            return ApiResponse.fail("景区修改失败");
        }

    }

    @Override
    public ApiResponse<Boolean> updateStatus(Long id) {
        int i = scenicMapper.updateStatus(id);
        if (i > 0) {
            scenicRepository.clearCache(id);
            return ApiResponse.success(true);
        }else {
            return ApiResponse.fail("景区状态修改失败");
        }
    }

    @Override
    public ApiResponse<Boolean> addConfig(ScenicConfigEntity scenicConfig) {
        if (scenicConfig.getId() == null) {
            scenicConfig.setId(SnowFlakeUtil.getLongId());
        }
        int i = scenicMapper.addConfig(scenicConfig);
        if (i > 0) {
            scenicRepository.clearCache(scenicConfig.getScenicId());
            return ApiResponse.success(true);
        }else {
            return ApiResponse.fail("景区配置添加失败");
        }
    }

    @Override
    public ApiResponse<Boolean> updateConfigById(ScenicConfigEntity scenicConfig) {
        int i = scenicMapper.updateConfigById(scenicConfig);
        if (i > 0) {
            scenicRepository.clearCache(scenicConfig.getScenicId());
            return ApiResponse.success(true);
        }else {
            return ApiResponse.fail("景区配置修改失败");
        }
    }

    @Override
    public ScenicConfigEntity getConfig(Long id) {
        return scenicRepository.getScenicConfig(id);
    }

    @Override
    public void saveConfig(Long configId, ScenicConfigEntity config) {
        config.setId(configId);
        if (config.getScenicId() == null) {
            throw new RuntimeException("景区ID不能为空");
        }
        scenicMapper.updateConfigById(config);
        scenicRepository.clearCache(config.getScenicId());
        scenicFaceBodyAdapterMap.remove(config.getScenicId());
        scenicStorageAdapterMap.remove(config.getScenicId());
        scenicTmpStorageAdapterMap.remove(config.getScenicId());
        scenicLocalStorageAdapterMap.remove(config.getScenicId());
        scenicPayAdapterMap.remove(config.getScenicId());
    }


    private static final Map<Long, IStorageAdapter> scenicStorageAdapterMap = new ConcurrentHashMap<>();
    @Override
    public IStorageAdapter getScenicStorageAdapter(Long scenicId) {
        return scenicStorageAdapterMap.computeIfAbsent(scenicId, (key) -> {
            IStorageAdapter adapter;
            ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
            if (scenicConfig != null && scenicConfig.getStoreType() != null) {
                try {
                    adapter = StorageFactory.get(scenicConfig.getStoreType());
                    adapter.loadConfig(JSONObject.parseObject(scenicConfig.getStoreConfigJson(), Map.class));
                } catch (StorageUnsupportedException ignored) {
                    return StorageFactory.use("video");
                }
            } else {
                adapter = StorageFactory.use("video");
            }
            return adapter;
        });
    }
    private static final Map<Long, IStorageAdapter> scenicTmpStorageAdapterMap = new ConcurrentHashMap<>();
    @Override
    public IStorageAdapter getScenicTmpStorageAdapter(Long scenicId) {
        return scenicTmpStorageAdapterMap.computeIfAbsent(scenicId, (key) -> {
            IStorageAdapter adapter;
            ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
            if (scenicConfig != null && scenicConfig.getTmpStoreType() != null) {
                try {
                    adapter = StorageFactory.get(scenicConfig.getTmpStoreType());
                    adapter.loadConfig(JSONObject.parseObject(scenicConfig.getTmpStoreConfigJson(), Map.class));
                } catch (StorageUnsupportedException ignored) {
                    return getScenicStorageAdapter(scenicId);
                }
            } else {
                return getScenicStorageAdapter(scenicId);
            }
            return adapter;
        });
    }
    private static final Map<Long, IStorageAdapter> scenicLocalStorageAdapterMap = new ConcurrentHashMap<>();
    @Override
    public IStorageAdapter getScenicLocalStorageAdapter(Long scenicId) {
        return scenicLocalStorageAdapterMap.computeIfAbsent(scenicId, (key) -> {
            IStorageAdapter adapter;
            ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
            if (scenicConfig != null && scenicConfig.getLocalStoreType() != null) {
                try {
                    adapter = StorageFactory.get(scenicConfig.getLocalStoreType());
                    adapter.loadConfig(JSONObject.parseObject(scenicConfig.getLocalStoreConfigJson(), Map.class));
                } catch (StorageUnsupportedException ignored) {
                    return getScenicStorageAdapter(scenicId);
                }
            } else {
                return getScenicStorageAdapter(scenicId);
            }
            return adapter;
        });
    }

    private static final Map<Long, IFaceBodyAdapter> scenicFaceBodyAdapterMap = new ConcurrentHashMap<>();
    @Override
    public IFaceBodyAdapter getScenicFaceBodyAdapter(Long scenicId) {
        return scenicFaceBodyAdapterMap.computeIfAbsent(scenicId, (key) -> {
            IFaceBodyAdapter adapter;
            ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
            if (scenicConfig != null && scenicConfig.getFaceType() != null) {
                adapter = FaceBodyFactory.getAdapter(scenicConfig.getFaceType());
                adapter.loadConfig(JSONObject.parseObject(scenicConfig.getFaceConfigJson(), Map.class));
            } else {
                adapter = FaceBodyFactory.use();
            }
            return adapter;
        });
    }

    private static final Map<Long, IPayAdapter> scenicPayAdapterMap = new ConcurrentHashMap<>();
    @Override
    public IPayAdapter getScenicPayAdapter(Long scenicId) {
        return scenicPayAdapterMap.computeIfAbsent(scenicId, (key) -> {
            IPayAdapter adapter;
            ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
            if (scenicConfig != null && scenicConfig.getPayType() != null) {
                adapter = PayFactory.getAdapter(scenicConfig.getPayType());
                adapter.loadConfig(JSONObject.parseObject(scenicConfig.getPayConfigJson(), Map.class));
            } else {
                adapter = PayFactory.use();
            }
            return adapter;
        });
    }
}
