package com.erp.service;

import com.erp.common.BaseService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
@RequiredArgsConstructor
@Slf4j
public class TemplateStandardService extends BaseService {

    private static final String NS = "templateStandard.";

    private final ObjectMapper objectMapper;

    /** JSON 필드(layout_config, default_size)를 문자열로 직렬화 */
    private void serializeJsonFields(Map<String, Object> params) {
        for (String field : List.of("layout_config", "default_size")) {
            Object val = params.get(field);
            if (val != null && !(val instanceof String)) {
                try {
                    params.put(field, objectMapper.writeValueAsString(val));
                } catch (Exception e) {
                    log.warn("JSON 직렬화 실패 ({}): {}", field, e.getMessage());
                }
            }
        }
    }

    /** DB에서 읽은 JSON 문자열 필드를 Object로 역직렬화 (snake_case 컬럼명 그대로) */
    private void deserializeJsonFields(Map<String, Object> row) {
        if (row == null) return;
        for (String field : List.of("layout_config", "default_size")) {
            Object val = row.get(field);
            if (val instanceof String s && !s.isBlank()) {
                try {
                    row.put(field, objectMapper.readValue(s, Object.class));
                } catch (Exception e) {
                    // 파싱 불가 시 문자열 그대로 유지
                }
            }
        }
    }

    private int toInt(Object val, int defaultVal) {
        if (val == null) return defaultVal;
        if (val instanceof Number n) return n.intValue();
        try { return Integer.parseInt(val.toString()); } catch (Exception e) { return defaultVal; }
    }

    /**
     * 템플릿 목록 조회 (페이지네이션 + 카운트 포함)
     */
    public Map<String, Object> getTemplateStandardList(Map<String, Object> params) {
        int page  = toInt(params.getOrDefault("page",  "1"),  1);
        int limit = toInt(params.getOrDefault("limit", "50"), 50);
        int offset = (page - 1) * limit;

        params.putIfAbsent("active",    "Y");
        params.putIfAbsent("is_public", "Y");
        params.put("page",   page);
        params.put("limit",  limit);
        params.put("offset", offset);

        List<Map<String, Object>> templates = sqlSession.selectList(NS + "getTemplateStandardList", params);
        templates.forEach(this::deserializeJsonFields);

        Integer totalObj = sqlSession.selectOne(NS + "getTemplateStandardListCnt", params);
        int total = totalObj != null ? totalObj : 0;

        Map<String, Object> result = new LinkedHashMap<>();
        result.put("templates", templates);
        result.put("total",     total);
        result.put("page",      page);
        result.put("limit",     limit);
        return result;
    }

    /**
     * 템플릿 단건 조회
     */
    public Map<String, Object> getTemplateStandardInfo(String templateCode) {
        Map<String, Object> params = new HashMap<>();
        params.put("template_code", templateCode);
        Map<String, Object> row = sqlSession.selectOne(NS + "getTemplateStandardInfo", params);
        deserializeJsonFields(row);
        return row;
    }

    /**
     * 템플릿 생성
     */
    @Transactional
    public Map<String, Object> insertTemplateStandard(Map<String, Object> params) {
        String templateCode = (String) params.get("template_code");

        Map<String, Object> checkParams = new HashMap<>();
        checkParams.put("template_code", templateCode);
        if (sqlSession.selectOne(NS + "getTemplateStandardInfo", checkParams) != null) {
            throw new IllegalArgumentException("템플릿 코드 '" + templateCode + "'는 이미 존재합니다.");
        }

        params.putIfAbsent("sort_order", 0);
        params.putIfAbsent("is_active",  "Y");
        params.putIfAbsent("is_public",  "N");
        serializeJsonFields(params);

        sqlSession.insert(NS + "insertTemplateStandard", params);

        return getTemplateStandardInfo(templateCode);
    }

    /**
     * 템플릿 수정
     */
    @Transactional
    public Map<String, Object> updateTemplateStandard(String templateCode, Map<String, Object> params) {
        params.put("template_code", templateCode);
        serializeJsonFields(params);

        int updated = sqlSession.update(NS + "updateTemplateStandard", params);
        if (updated == 0) return null;

        return getTemplateStandardInfo(templateCode);
    }

    /**
     * 템플릿 삭제
     */
    @Transactional
    public boolean deleteTemplateStandard(String templateCode) {
        Map<String, Object> params = new HashMap<>();
        params.put("template_code", templateCode);
        return sqlSession.delete(NS + "deleteTemplateStandard", params) > 0;
    }

    /**
     * 정렬 순서 일괄 업데이트
     */
    @Transactional
    public void updateTemplateStandardSortOrder(List<Map<String, Object>> templates) {
        for (Map<String, Object> t : templates) {
            sqlSession.update(NS + "updateTemplateStandardSortOrder", t);
        }
    }

    /**
     * 템플릿 복제
     */
    @Transactional
    public Map<String, Object> duplicateTemplateStandard(Map<String, Object> params) {
        String originalCode = (String) params.get("original_code");
        String newCode      = (String) params.get("new_code");
        String newName      = (String) params.get("new_name");
        String companyCode  = (String) params.get("company_code");
        String createdBy    = (String) params.get("created_by");

        Map<String, Object> original = getTemplateStandardInfo(originalCode);
        if (original == null) {
            throw new IllegalArgumentException("원본 템플릿을 찾을 수 없습니다.");
        }

        Map<String, Object> checkParams = new HashMap<>();
        checkParams.put("template_code", newCode);
        if (sqlSession.selectOne(NS + "getTemplateStandardInfo", checkParams) != null) {
            throw new IllegalArgumentException("템플릿 코드 '" + newCode + "'는 이미 존재합니다.");
        }

        // 원본 기반 신규 템플릿 데이터 구성 (DB 결과는 snake_case)
        Map<String, Object> newTemplate = new LinkedHashMap<>();
        newTemplate.put("template_code",     newCode);
        newTemplate.put("template_name",     newName);
        String origEngName = (String) original.get("template_name_eng");
        newTemplate.put("template_name_eng", origEngName != null ? origEngName + " (Copy)" : null);
        newTemplate.put("description",    original.get("description"));
        newTemplate.put("category",       original.get("category"));
        newTemplate.put("icon_name",      original.get("icon_name"));
        newTemplate.put("default_size",   original.get("default_size"));
        newTemplate.put("layout_config",  original.get("layout_config"));
        newTemplate.put("preview_image",  original.get("preview_image"));
        newTemplate.put("sort_order",     0);
        newTemplate.put("is_active",      "Y");
        newTemplate.put("is_public",      "N");
        newTemplate.put("company_code",   companyCode);
        newTemplate.put("created_by",     createdBy);
        newTemplate.put("updated_by",     createdBy);

        // layout_config / default_size가 이미 Object이면 직렬화
        serializeJsonFields(newTemplate);

        sqlSession.insert(NS + "insertTemplateStandard", newTemplate);
        return getTemplateStandardInfo(newCode);
    }

    /**
     * 카테고리 목록 조회
     */
    public List<String> getTemplateStandardCategoryList(String companyCode) {
        Map<String, Object> params = new HashMap<>();
        params.put("company_code", companyCode);
        List<Map<String, Object>> rows = sqlSession.selectList(NS + "getTemplateStandardCategoryList", params);
        List<String> categories = new ArrayList<>();
        for (Map<String, Object> row : rows) {
            Object cat = row.get("category");
            if (cat != null) categories.add(cat.toString());
        }
        return categories;
    }
}
