package com.erp.controller;

import com.erp.dto.ApiResponse;
import com.erp.service.EntityJoinService;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Entity 조인 API 컨트롤러.
 * Node.js /api/table-management/* 라우트와 동일한 경로/응답 형식을 제공한다.
 */
@RestController
@RequestMapping("/api/table-management")
@RequiredArgsConstructor
@Slf4j
public class EntityJoinController {

    private final EntityJoinService entityJoinService;
    private final ObjectMapper objectMapper;

    // ════════════════════════════════════════════════════════════════════════
    // Entity 조인 데이터 조회
    // ════════════════════════════════════════════════════════════════════════

    /**
     * GET /api/table-management/tables/{tableName}/data-with-joins
     * Entity 조인이 포함된 테이블 데이터 조회 (페이지네이션)
     */
    @GetMapping("/tables/{tableName}/data-with-joins")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getTableDataWithJoins(
            @PathVariable String tableName,
            @RequestAttribute("company_code") String companyCode,
            @RequestParam Map<String, Object> queryParams) {

        Map<String, Object> options = new HashMap<>(queryParams);
        options.put("company_code", companyCode);

        // search 파라미터 JSON 파싱
        Object searchRaw = queryParams.get("search");
        if (searchRaw instanceof String s && !s.isBlank()) {
            try {
                options.put("search", objectMapper.readValue(s, new TypeReference<Map<String, Object>>() {}));
            } catch (Exception e) {
                log.warn("search 파싱 실패: {}", e.getMessage());
                options.remove("search");
            }
        }

        // autoFilter 파싱 (멀티테넌시)
        Object autoFilterRaw = queryParams.get("auto_filter");
        if (autoFilterRaw instanceof String af && !af.isBlank()) {
            try {
                Map<String, Object> autoFilter = objectMapper.readValue(af, new TypeReference<>() {});
                Boolean enabled = (Boolean) autoFilter.getOrDefault("enabled", false);
                if (Boolean.TRUE.equals(enabled)) {
                    String filterColumn = (String) autoFilter.getOrDefault("filter_column", "company_code");
                    Map<String, Object> search = getOrCreateSearch(options);
                    String finalCode = companyCode;
                    if ("*".equals(companyCode) && autoFilter.get("company_code_override") != null) {
                        finalCode = (String) autoFilter.get("company_code_override");
                    }
                    search.put(filterColumn, finalCode);
                    options.put("search", search);
                }
            } catch (Exception e) {
                log.warn("autoFilter 파싱 실패: {}", e.getMessage());
            }
        }

        Map<String, Object> result = entityJoinService.getTableDataWithJoins(tableName, options);
        return ResponseEntity.ok(ApiResponse.success(result, "Entity 조인 데이터 조회 성공"));
    }

    // ════════════════════════════════════════════════════════════════════════
    // Entity 조인 설정 관리
    // ════════════════════════════════════════════════════════════════════════

    /**
     * GET /api/table-management/tables/{tableName}/entity-joins
     * 테이블의 Entity 조인 설정 조회
     */
    @GetMapping("/tables/{tableName}/entity-joins")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getEntityJoinConfigs(
            @PathVariable String tableName,
            @RequestAttribute("company_code") String companyCode) {

        List<Map<String, Object>> joinConfigs =
                entityJoinService.detectEntityJoins(tableName, null, companyCode);

        Map<String, Object> data = new HashMap<>();
        data.put("table_name", tableName);
        data.put("join_configs", joinConfigs);
        data.put("count", joinConfigs.size());
        return ResponseEntity.ok(ApiResponse.success(data, "Entity 조인 설정 조회 성공"));
    }

    /**
     * PUT /api/table-management/tables/{tableName}/columns/{columnName}/entity-settings
     * 컬럼 Entity 설정 업데이트 (display_column 포함)
     */
    @PutMapping("/tables/{tableName}/columns/{columnName}/entity-settings")
    public ResponseEntity<ApiResponse<Map<String, Object>>> updateEntitySettings(
            @PathVariable String tableName,
            @PathVariable String columnName,
            @RequestAttribute("company_code") String companyCode,
            @RequestBody Map<String, Object> body) {

        String webType = (String) body.get("web_type");
        String referenceTable  = (String) body.get("reference_table");
        String referenceColumn = (String) body.get("reference_column");

        if ("entity".equals(webType) && (referenceTable == null || referenceColumn == null)) {
            return ResponseEntity.badRequest()
                    .body(ApiResponse.error("Entity 타입의 경우 referenceTable과 referenceColumn이 필수입니다."));
        }

        entityJoinService.updateColumnEntitySettings(tableName, columnName, body, companyCode);

        // 관련 캐시 무효화
        if ("entity".equals(webType) && referenceTable != null) {
            String displayColumn = (String) body.get("display_column");
            String referenceColVal = (String) body.get("reference_column");
            entityJoinService.invalidateCache(referenceTable, referenceColVal, displayColumn);
        }

        Map<String, Object> data = new HashMap<>();
        data.put("table_name", tableName);
        data.put("column_name", columnName);
        data.put("settings", Map.of(
                "web_type", webType != null ? webType : "",
                "reference_table",  referenceTable  != null ? referenceTable  : "",
                "reference_column", referenceColumn != null ? referenceColumn : "",
                "display_column",   body.getOrDefault("display_column", "")));
        return ResponseEntity.ok(ApiResponse.success(data, "Entity 설정 업데이트 성공"));
    }

    // ════════════════════════════════════════════════════════════════════════
    // 참조 테이블 정보
    // ════════════════════════════════════════════════════════════════════════

    /**
     * GET /api/table-management/tables/{tableName}/entity-join-columns
     * Entity 조인된 테이블의 추가 컬럼 목록 조회 (화면편집기용)
     */
    @GetMapping("/tables/{tableName}/entity-join-columns")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getEntityJoinColumns(
            @PathVariable String tableName,
            @RequestAttribute("company_code") String companyCode) {

        Map<String, Object> result = entityJoinService.getEntityJoinColumns(tableName, companyCode);
        return ResponseEntity.ok(ApiResponse.success(result, "Entity 조인 컬럼 조회 성공"));
    }

    /**
     * GET /api/table-management/reference-tables/{tableName}/columns
     * 참조 테이블의 표시 가능한 컬럼 목록 조회
     */
    @GetMapping("/reference-tables/{tableName}/columns")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getReferenceTableColumns(
            @PathVariable String tableName,
            @RequestAttribute("company_code") String companyCode) {

        List<Map<String, Object>> columns =
                entityJoinService.getReferenceTableColumns(tableName, companyCode);

        Map<String, Object> data = new HashMap<>();
        data.put("table_name", tableName);
        data.put("columns", columns);
        data.put("count", columns.size());
        return ResponseEntity.ok(ApiResponse.success(data, "참조 테이블 컬럼 조회 성공"));
    }

    // ════════════════════════════════════════════════════════════════════════
    // 캐시 관리
    // ════════════════════════════════════════════════════════════════════════

    /**
     * GET /api/table-management/cache/status
     * 캐시 상태 조회
     */
    @GetMapping("/cache/status")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getCacheStatus() {
        return ResponseEntity.ok(ApiResponse.success(entityJoinService.getCacheStatus(), "캐시 상태 조회 성공"));
    }

    /**
     * DELETE /api/table-management/cache
     * 캐시 무효화 (table/keyColumn/displayColumn 지정 시 부분 무효화)
     */
    @DeleteMapping("/cache")
    public ResponseEntity<ApiResponse<Map<String, Object>>> invalidateCache(
            @RequestParam(required = false) String table,
            @RequestParam(required = false) String keyColumn,
            @RequestParam(required = false) String displayColumn) {

        entityJoinService.invalidateCache(table, keyColumn, displayColumn);

        Map<String, Object> data = new HashMap<>();
        data.put("target", (table != null)
                ? table + "." + keyColumn + "." + displayColumn
                : "전체");
        return ResponseEntity.ok(ApiResponse.success(data, "캐시 무효화 완료"));
    }

    /**
     * POST /api/table-management/cache/preload
     * 공통 참조 테이블 자동 캐싱
     */
    @PostMapping("/cache/preload")
    public ResponseEntity<ApiResponse<Map<String, Object>>> preloadCommonCaches() {
        entityJoinService.preloadCommonCaches();
        Map<String, Object> cacheStatus = entityJoinService.getCacheStatus();

        @SuppressWarnings("unchecked")
        List<Map<String, Object>> caches = (List<Map<String, Object>>) cacheStatus.get("caches");
        Map<String, Object> data = new HashMap<>();
        data.put("preloaded_caches", caches != null ? caches.size() : 0);
        data.put("caches", caches);
        return ResponseEntity.ok(ApiResponse.success(data, "공통 참조 테이블 캐싱 완료"));
    }

    // ─── 내부 유틸 ──────────────────────────────────────────────────────────

    @SuppressWarnings("unchecked")
    private Map<String, Object> getOrCreateSearch(Map<String, Object> options) {
        Object existing = options.get("search");
        if (existing instanceof Map) return (Map<String, Object>) existing;
        Map<String, Object> search = new HashMap<>();
        options.put("search", search);
        return search;
    }
}
