package com.hotwj.platform.reportStatistics.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hotwj.platform.reportStatistics.domain.SysReportTemplate;
import com.hotwj.platform.reportStatistics.domain.bo.SysReportTemplateBo;
import com.hotwj.platform.reportStatistics.domain.vo.SysReportTemplateVo;
import com.hotwj.platform.reportStatistics.mapper.SysReportTemplateMapper;
import com.hotwj.platform.reportStatistics.service.IReportDataProvider;
import com.hotwj.platform.reportStatistics.service.ISysReportTemplateService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * 报表模板Service业务层处理
 *
 * @author shihongwei
 * @date 2024-03-15
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SysReportTemplateServiceImpl implements ISysReportTemplateService {

    private final SysReportTemplateMapper baseMapper;
    private final List<IReportDataProvider> reportDataProviders;

    /**
     * 根据模板编码查找对应的 Provider
     */
    @Override
    public IReportDataProvider findProviderByTemplateCode(String templateCode) {
        if (reportDataProviders == null || StringUtils.isBlank(templateCode)) {
            return null;
        }
        for (IReportDataProvider provider : reportDataProviders) {
            if (templateCode.equals(provider.getTemplateCode())) {
                return provider;
            }
        }
        return null;
    }

    /**
     * 查询报表模板
     */
    @Override
    public SysReportTemplateVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询报表模板
     */
    @Override
    public SysReportTemplateVo queryByCode(String code) {
        return baseMapper.selectVoOne(new LambdaQueryWrapper<SysReportTemplate>().eq(SysReportTemplate::getTemplateCode, code));
    }

    /**
     * 查询报表模板列表
     */
    @Override
    public TableDataInfo<SysReportTemplateVo> queryPageList(SysReportTemplateBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SysReportTemplate> lqw = buildQueryWrapper(bo);
        Page<SysReportTemplateVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询报表模板列表
     */
    @Override
    public List<SysReportTemplateVo> queryList(SysReportTemplateBo bo) {
        LambdaQueryWrapper<SysReportTemplate> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<SysReportTemplate> buildQueryWrapper(SysReportTemplateBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<SysReportTemplate> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getTemplateCode()), SysReportTemplate::getTemplateCode, bo.getTemplateCode());
        lqw.like(StringUtils.isNotBlank(bo.getTemplateName()), SysReportTemplate::getTemplateName, bo.getTemplateName());
        lqw.eq(StringUtils.isNotBlank(bo.getRemark()), SysReportTemplate::getRemark, bo.getRemark());
        return lqw;
    }

    /**
     * 新增报表模板
     */
    @Override
    public Boolean insertByBo(SysReportTemplateBo bo) {
        SysReportTemplate add = MapstructUtils.convert(bo, SysReportTemplate.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改报表模板
     */
    @Override
    public Boolean updateByBo(SysReportTemplateBo bo) {
        SysReportTemplate update = MapstructUtils.convert(bo, SysReportTemplate.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(SysReportTemplate entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除报表模板
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 同步 Classpath 下的模版到数据库
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncTemplatesFromClasspath() {
        // 1. Sync from Providers (Source of truth for Title and MockData)
        if (reportDataProviders != null) {
            for (IReportDataProvider provider : reportDataProviders) {
                try {
                    String code = provider.getTemplateCode();
                    if (StringUtils.isBlank(code)) continue;

                    SysReportTemplateVo existing = queryByCode(code);

                    // Read content
                    String content = null;
                    try {
                        ClassPathResource resource = new ClassPathResource(code);
                        if (resource.exists()) {
                            content = IoUtil.read(resource.getInputStream(), StandardCharsets.UTF_8);
                        }
                    } catch (Exception e) {
                        log.warn("Template file not found for provider: {}", provider.getClass().getSimpleName());
                    }

                    if (existing == null) {
                        if (StringUtils.isBlank(content)) {
                            log.warn("Skipping provider {} because template file {} not found", provider.getClass().getSimpleName(), code);
                            continue;
                        }
                        SysReportTemplate template = new SysReportTemplate();
                        template.setTemplateCode(code);
                        template.setTemplateName(provider.getReportTitle());
                        template.setContent(content);
                        template.setMockData(provider.getMockData());
                        template.setVersion(1);
                        template.setRemark("Synced from Provider: " + provider.getClass().getSimpleName());
                        baseMapper.insert(template);
                        log.info("Inserted template from provider: {}", code);
                    } else {
                        // Update metadata
                        SysReportTemplate update = new SysReportTemplate();
                        update.setId(existing.getId());
                        boolean changed = false;

                        // Sync Title
                        String title = provider.getReportTitle();
                        if (StringUtils.isNotBlank(title) && !title.equals(existing.getTemplateName())) {
                            update.setTemplateName(title);
                            changed = true;
                        }

                        // Sync MockData if provided
                        Map<String, Object> mockData = provider.getMockData();
                        if (mockData != null && !mockData.isEmpty()) {
                            update.setMockData(mockData);
                            changed = true;
                        }

                        // Optional: Sync content if it was empty in DB (unlikely)
                        if (StringUtils.isBlank(existing.getContent()) && StringUtils.isNotBlank(content)) {
                            update.setContent(content);
                            changed = true;
                        }

                        if (changed) {
                            baseMapper.updateById(update);
                            log.info("Updated template metadata from provider: {}", code);
                        }
                    }
                } catch (Exception e) {
                    log.error("Error syncing provider template: " + provider.getClass().getSimpleName(), e);
                }
            }
        }

        // 2. Scan remaining files (for layouts and fragments)
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            // Find all .vm files in templates directory
            Resource[] resources = resolver.getResources("classpath*:templates/**/*.vm");
            for (Resource resource : resources) {
                try {
                    String path = resource.getURL().getPath();
                    // Normalize path separators
                    path = path.replace("\\", "/");

                    int index = path.lastIndexOf("templates/");
                    if (index > -1) {
                        String code = path.substring(index); // Include "templates/" in the code

                        // Check if exists
                        SysReportTemplateVo exist = queryByCode(code);
                        if (exist == null) {
                            String content = IoUtil.read(resource.getInputStream(), StandardCharsets.UTF_8);
                            SysReportTemplate template = new SysReportTemplate();
                            template.setTemplateCode(code);
                            // Use filename as name
                            template.setTemplateName(FileUtil.mainName(resource.getFilename()));
                            template.setContent(content);
                            template.setVersion(1);
                            template.setRemark("Synced from classpath scan");
                            baseMapper.insert(template);
                            log.info("Synced template from scan: {}", code);
                        }
                    }
                } catch (Exception e) {
                    log.error("Error processing resource: " + resource, e);
                }
            }
        } catch (IOException e) {
            log.error("Failed to sync templates", e);
            throw new ServiceException("同步模版失败");
        }
    }
}
