package com.erp.controller;

import com.erp.dto.ApiResponse;
import com.erp.service.ExternalDbConnectionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * 외부 DB 연결 관리 API
 * Base: /api/external-db-connections
 *
 * 경로 우선순위 (Spring MVC: 리터럴 > 변수):
 *  GET  /types/supported, /pool-status, /grouped, /control/active  → literal (먼저 매핑)
 *  GET  /{id}                                                        → variable
 *  GET  /{id}/tables/{tableName}/columns                             → 3-segment path
 */
@RestController
@RequestMapping("/api/external-db-connections")
@RequiredArgsConstructor
@Slf4j
public class ExternalDbConnectionController {

    private final ExternalDbConnectionService service;

    // ── 지원 DB 타입 목록 ──────────────────────────────────────────────────────

    /**
     * GET /api/external-db-connections/types/supported
     */
    @GetMapping("/types/supported")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getSupportedTypes(
            @RequestAttribute("company_code") String companyCode) {
        return ResponseEntity.ok(
            ApiResponse.success(service.getSupportedTypes(), "지원하는 DB 타입 목록을 조회했습니다."));
    }

    // ── 연결 풀 상태 ────────────────────────────────────────────────────────────

    /**
     * GET /api/external-db-connections/pool-status
     */
    @GetMapping("/pool-status")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getPoolStatus(
            @RequestAttribute("company_code") String companyCode) {
        Map<String, Object> status = service.getPoolStatus();
        String msg = status.get("total_pools") + "개의 연결 풀 상태를 조회했습니다.";
        return ResponseEntity.ok(ApiResponse.success(status, msg));
    }

    // ── 그룹화된 목록 조회 ─────────────────────────────────────────────────────

    /**
     * GET /api/external-db-connections/grouped
     */
    @GetMapping("/grouped")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getConnectionsGroupedByType(
            @RequestAttribute("company_code") String companyCode,
            @RequestParam Map<String, Object> queryParams) {
        buildFilter(queryParams, companyCode, (String) queryParams.get("company_code"));
        Map<String, Object> grouped = service.getConnectionsGroupedByType(queryParams);
        return ResponseEntity.ok(
            ApiResponse.success(grouped, "DB 타입별로 그룹화된 연결 목록을 조회했습니다."));
    }

    // ── 제어관리용 활성 연결 목록 ─────────────────────────────────────────────

    /**
     * GET /api/external-db-connections/control/active
     */
    @GetMapping("/control/active")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getActiveConnectionsForControl(
            @RequestAttribute("company_code") String companyCode,
            @RequestParam(required = false) String company_code) {
        Map<String, Object> params = new HashMap<>();
        buildFilter(params, companyCode, company_code);
        List<Map<String, Object>> list = service.getActiveConnectionsForControl(params);
        return ResponseEntity.ok(
            ApiResponse.success(list, "제어관리용 활성 커넥션 목록을 조회했습니다."));
    }

    // ── 목록 조회 ──────────────────────────────────────────────────────────────

    /**
     * GET /api/external-db-connections
     */
    @GetMapping
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getConnections(
            @RequestAttribute("company_code") String companyCode,
            @RequestParam Map<String, Object> queryParams) {
        buildFilter(queryParams, companyCode, (String) queryParams.get("company_code"));
        List<Map<String, Object>> list = service.getConnections(queryParams);
        return ResponseEntity.ok(
            ApiResponse.success(list, list.size() + "개의 연결 설정을 조회했습니다."));
    }

    // ── 단건 조회 ──────────────────────────────────────────────────────────────

    /**
     * GET /api/external-db-connections/{id}
     */
    @GetMapping("/{id}")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getConnectionById(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable long id) {
        Map<String, Object> conn = service.getConnectionById(id);
        if (conn == null) {
            return ResponseEntity.status(404)
                .body(ApiResponse.error("해당 연결 설정을 찾을 수 없습니다."));
        }
        return ResponseEntity.ok(ApiResponse.success(conn, "연결 설정을 조회했습니다."));
    }

    // ── 생성 ───────────────────────────────────────────────────────────────────

    /**
     * POST /api/external-db-connections
     */
    @PostMapping
    public ResponseEntity<ApiResponse<Map<String, Object>>> createConnection(
            @RequestAttribute("company_code") String companyCode,
            @RequestAttribute("user_id") String userId,
            @RequestBody Map<String, Object> body) {
        body.put("created_by", userId);
        body.put("updated_by", userId);
        try {
            Map<String, Object> created = service.createConnection(body);
            return ResponseEntity.status(201)
                .body(ApiResponse.success(created, "연결 설정이 생성되었습니다."));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
        }
    }

    // ── 수정 ───────────────────────────────────────────────────────────────────

    /**
     * PUT /api/external-db-connections/{id}
     */
    @PutMapping("/{id}")
    public ResponseEntity<ApiResponse<Map<String, Object>>> updateConnection(
            @RequestAttribute("company_code") String companyCode,
            @RequestAttribute("user_id") String userId,
            @PathVariable long id,
            @RequestBody Map<String, Object> body) {
        body.put("updated_by", userId);
        try {
            Map<String, Object> updated = service.updateConnection(id, body);
            return ResponseEntity.ok(ApiResponse.success(updated, "연결 설정이 수정되었습니다."));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
        } catch (NoSuchElementException e) {
            return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
        }
    }

    // ── 삭제 ───────────────────────────────────────────────────────────────────

    /**
     * DELETE /api/external-db-connections/{id}
     */
    @DeleteMapping("/{id}")
    public ResponseEntity<ApiResponse<Void>> deleteConnection(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable long id) {
        try {
            service.deleteConnection(id, companyCode);
            return ResponseEntity.ok(ApiResponse.success(null, "연결 설정이 삭제되었습니다."));
        } catch (NoSuchElementException e) {
            return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
        }
    }

    // ── 연결 테스트 ────────────────────────────────────────────────────────────

    /**
     * POST /api/external-db-connections/{id}/test
     */
    @PostMapping("/{id}/test")
    public ResponseEntity<ApiResponse<Map<String, Object>>> testConnection(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable long id,
            @RequestBody(required = false) Map<String, Object> body) {
        String testPassword = body != null ? (String) body.get("password") : null;
        Map<String, Object> result = service.testConnectionById(id, testPassword);
        return ResponseEntity.ok(ApiResponse.success(result,
            Boolean.TRUE.equals(result.get("success")) ? "연결 성공" : "연결 실패"));
    }

    // ── 쿼리 실행 ──────────────────────────────────────────────────────────────

    /**
     * POST /api/external-db-connections/{id}/execute
     */
    @PostMapping("/{id}/execute")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> executeQuery(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable long id,
            @RequestBody Map<String, Object> body) {
        String sql = (String) body.get("query");
        if (sql == null || sql.isBlank()) {
            return ResponseEntity.badRequest()
                .body(ApiResponse.error("쿼리가 입력되지 않았습니다."));
        }
        try {
            Map<String, Object> result = service.executeQuery(id, sql);
            @SuppressWarnings("unchecked")
            List<Map<String, Object>> rows = (List<Map<String, Object>>) result.get("data");
            return ResponseEntity.ok(
                ApiResponse.success(rows, "쿼리가 성공적으로 실행되었습니다."));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
        } catch (UnsupportedOperationException e) {
            return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
        }
    }

    // ── 테이블 목록 ────────────────────────────────────────────────────────────

    /**
     * GET /api/external-db-connections/{id}/tables
     */
    @GetMapping("/{id}/tables")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTables(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable long id) {
        try {
            List<Map<String, Object>> tables = service.getTables(id);
            return ResponseEntity.ok(
                ApiResponse.success(tables, "테이블 목록을 조회했습니다."));
        } catch (NoSuchElementException e) {
            return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
        }
    }

    // ── 테이블 컬럼 목록 ────────────────────────────────────────────────────────

    /**
     * GET /api/external-db-connections/{id}/tables/{tableName}/columns
     */
    @GetMapping("/{id}/tables/{tableName}/columns")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTableColumns(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable long id,
            @PathVariable String tableName) {
        if (tableName == null || tableName.isBlank()) {
            return ResponseEntity.badRequest()
                .body(ApiResponse.error("테이블명이 입력되지 않았습니다."));
        }
        try {
            List<Map<String, Object>> columns = service.getTableColumns(id, tableName);
            return ResponseEntity.ok(
                ApiResponse.success(columns, "컬럼 정보를 조회했습니다."));
        } catch (NoSuchElementException e) {
            return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
        }
    }

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

    /**
     * company_code 필터 적용.
     * SUPER_ADMIN("*"): 쿼리 파라미터 company_code 우선, 없으면 전체 조회
     * 일반 사용자: 자사 코드 강제 적용
     */
    private void buildFilter(Map<String, Object> params, String userCompanyCode, String queryCompanyCode) {
        if ("*".equals(userCompanyCode)) {
            // SUPER_ADMIN: query param이 있으면 그것, 없으면 전체(null → WHERE 없음)
            if (queryCompanyCode != null && !queryCompanyCode.isBlank()) {
                params.put("filter_company_code", queryCompanyCode);
            }
            // filterCompanyCode 없으면 전체 조회
        } else {
            // 일반 사용자: 강제 적용
            params.put("filter_company_code", userCompanyCode);
        }
    }
}
