package com.erp.controller;

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

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

@RestController
@RequestMapping("/api/numbering-rules")
@RequiredArgsConstructor
@Slf4j
public class NumberingRuleController {

    private final NumberingRuleService numberingRuleService;

    // ================================================================
    // ■ 규칙 목록 / 단건 조회
    // ================================================================

    /** GET / → 회사별 채번 규칙 전체 목록 */
    @GetMapping
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getRuleList(
            @RequestAttribute("company_code") String companyCode) {
        List<Map<String, Object>> list = numberingRuleService.getRuleList(companyCode);
        return ResponseEntity.ok(ApiResponse.success(list, "채번 규칙 목록을 조회했습니다."));
    }

    /** GET /available → 메뉴 기반 사용 가능 규칙 (menuObjid 없음) */
    @GetMapping("/available")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getAvailableRulesForMenu(
            @RequestAttribute("company_code") String companyCode) {
        List<Map<String, Object>> list = numberingRuleService.getAvailableRulesForMenu(companyCode, null);
        return ResponseEntity.ok(ApiResponse.success(list, "사용 가능한 채번 규칙을 조회했습니다."));
    }

    /** GET /available/{menuObjid} → 메뉴 기반 사용 가능 규칙 */
    @GetMapping("/available/{menuObjid}")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getAvailableRulesForMenuWithId(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable String menuObjid) {
        List<Map<String, Object>> list = numberingRuleService.getAvailableRulesForMenu(companyCode, menuObjid);
        return ResponseEntity.ok(ApiResponse.success(list, "사용 가능한 채번 규칙을 조회했습니다."));
    }

    /** GET /available-for-screen?tableName= → 화면 기반 사용 가능 규칙 */
    @GetMapping("/available-for-screen")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getAvailableRulesForScreen(
            @RequestAttribute("company_code") String companyCode,
            @RequestParam(required = false) String tableName) {
        List<Map<String, Object>> list = numberingRuleService.getAvailableRulesForScreen(companyCode, tableName);
        return ResponseEntity.ok(ApiResponse.success(list, "화면별 채번 규칙을 조회했습니다."));
    }

    /** GET /by-column/{tableName}/{columnName} → 테이블+컬럼 기반 규칙 조회 */
    @GetMapping("/by-column/{tableName}/{columnName}")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getNumberingRuleByColumn(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable String tableName,
            @PathVariable String columnName) {
        Map<String, Object> rule = numberingRuleService.getNumberingRuleByColumn(
                companyCode, tableName, columnName);
        if (rule == null) {
            return ResponseEntity.ok(ApiResponse.success(null, "채번 규칙을 찾을 수 없습니다."));
        }
        return ResponseEntity.ok(ApiResponse.success(rule, "채번 규칙을 조회했습니다."));
    }

    // ================================================================
    // ■ 테스트 테이블 Operations
    // ================================================================

    /** GET /test/list → 테스트용 규칙 목록 */
    @GetMapping("/test/list")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getRulesFromTest(
            @RequestAttribute("company_code") String companyCode) {
        List<Map<String, Object>> list = numberingRuleService.getRulesFromTest(companyCode, null);
        return ResponseEntity.ok(ApiResponse.success(list, "테스트 채번 규칙 목록을 조회했습니다."));
    }

    /** GET /test/list/{menuObjid} → 테스트용 규칙 목록 (메뉴 필터) */
    @GetMapping("/test/list/{menuObjid}")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getRulesFromTestWithMenu(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable String menuObjid) {
        List<Map<String, Object>> list = numberingRuleService.getRulesFromTest(companyCode, menuObjid);
        return ResponseEntity.ok(ApiResponse.success(list, "테스트 채번 규칙 목록을 조회했습니다."));
    }

    /** GET /test/by-column/{tableName}/{columnName} → 테스트 테이블+컬럼 기반 조회 */
    @GetMapping("/test/by-column/{tableName}/{columnName}")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getTestRuleByColumn(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable String tableName,
            @PathVariable String columnName) {
        Map<String, Object> rule = numberingRuleService.getNumberingRuleByColumn(
                companyCode, tableName, columnName);
        if (rule == null) {
            return ResponseEntity.ok(ApiResponse.success(null, "채번 규칙을 찾을 수 없습니다."));
        }
        return ResponseEntity.ok(ApiResponse.success(rule, "채번 규칙을 조회했습니다."));
    }

    /** POST /test/save → UPSERT */
    @PostMapping("/test/save")
    public ResponseEntity<ApiResponse<Map<String, Object>>> saveRuleToTest(
            @RequestAttribute("company_code") String companyCode,
            @RequestBody Map<String, Object> body) {
        if (body.get("rule_id") == null || body.get("rule_name") == null) {
            return ResponseEntity.badRequest().body(ApiResponse.error("ruleId와 ruleName이 필요합니다."));
        }
        Map<String, Object> result = numberingRuleService.saveRuleToTest(body, companyCode);
        return ResponseEntity.ok(ApiResponse.success(result, "테스트 채번 규칙이 저장되었습니다."));
    }

    /** DELETE /test/{ruleId} → 테스트 규칙 삭제 */
    @DeleteMapping("/test/{ruleId}")
    public ResponseEntity<ApiResponse<Void>> deleteRuleFromTest(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable String ruleId) {
        numberingRuleService.deleteRuleFromTest(ruleId, companyCode);
        return ResponseEntity.ok(ApiResponse.success(null, "테스트 채번 규칙이 삭제되었습니다."));
    }

    /** POST /test/{ruleId}/preview → 테스트 미리보기 */
    @PostMapping("/test/{ruleId}/preview")
    public ResponseEntity<ApiResponse<Map<String, Object>>> previewCodeFromTest(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable String ruleId,
            @RequestBody(required = false) Map<String, Object> body) {
        @SuppressWarnings("unchecked")
        Map<String, Object> formData = body != null ? (Map<String, Object>) body.get("form_data") : null;
        String manualInputValue = body != null ? (String) body.get("manual_input_value") : null;
        String code = numberingRuleService.previewCode(ruleId, companyCode, formData, manualInputValue);
        return ResponseEntity.ok(ApiResponse.success(Map.of("generatedCode", code), "미리보기 생성이 완료되었습니다."));
    }

    // ================================================================
    // ■ 단건 CRUD
    // ================================================================

    /** GET /{ruleId} → 단건 조회 */
    @GetMapping("/{ruleId}")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getRuleById(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable String ruleId) {
        Map<String, Object> rule = numberingRuleService.getRuleById(ruleId, companyCode);
        if (rule == null) {
            return ResponseEntity.ok(ApiResponse.success(null, "채번 규칙을 찾을 수 없습니다."));
        }
        return ResponseEntity.ok(ApiResponse.success(rule, "채번 규칙을 조회했습니다."));
    }

    /** POST / → 규칙 생성 */
    @PostMapping
    public ResponseEntity<ApiResponse<Map<String, Object>>> createRule(
            @RequestAttribute("company_code") String companyCode,
            @RequestAttribute(value = "user_id", required = false) String userId,
            @RequestBody Map<String, Object> body) {
        if (body.get("rule_id") == null || body.get("rule_name") == null || body.get("parts") == null) {
            return ResponseEntity.badRequest().body(ApiResponse.error("ruleId, ruleName, parts가 필요합니다."));
        }
        if (userId != null) body.put("user_id", userId);
        Map<String, Object> result = numberingRuleService.createRule(body, companyCode);
        return ResponseEntity.status(201).body(ApiResponse.success(result, "채번 규칙이 생성되었습니다."));
    }

    /** PUT /{ruleId} → 규칙 수정 */
    @PutMapping("/{ruleId}")
    public ResponseEntity<ApiResponse<Map<String, Object>>> updateRule(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable String ruleId,
            @RequestBody Map<String, Object> body) {
        Map<String, Object> result = numberingRuleService.updateRule(ruleId, body, companyCode);
        return ResponseEntity.ok(ApiResponse.success(result, "채번 규칙이 수정되었습니다."));
    }

    /** DELETE /{ruleId} → 규칙 삭제 */
    @DeleteMapping("/{ruleId}")
    public ResponseEntity<ApiResponse<Void>> deleteRule(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable String ruleId) {
        numberingRuleService.deleteRule(ruleId, companyCode);
        return ResponseEntity.ok(ApiResponse.success(null, "채번 규칙이 삭제되었습니다."));
    }

    // ================================================================
    // ■ 코드 생성 Actions
    // ================================================================

    /** POST /{ruleId}/preview → 미리보기 (순번 증가 없음) */
    @PostMapping("/{ruleId}/preview")
    public ResponseEntity<ApiResponse<Map<String, Object>>> previewCode(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable String ruleId,
            @RequestBody(required = false) Map<String, Object> body) {
        @SuppressWarnings("unchecked")
        Map<String, Object> formData = body != null ? (Map<String, Object>) body.get("form_data") : null;
        String manualInputValue = body != null ? (String) body.get("manual_input_value") : null;
        String code = numberingRuleService.previewCode(ruleId, companyCode, formData, manualInputValue);
        return ResponseEntity.ok(ApiResponse.success(Map.of("generatedCode", code), "미리보기 생성이 완료되었습니다."));
    }

    /** POST /{ruleId}/allocate → 코드 할당 (순번 증가) */
    @PostMapping("/{ruleId}/allocate")
    public ResponseEntity<ApiResponse<Map<String, Object>>> allocateCode(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable String ruleId,
            @RequestBody(required = false) Map<String, Object> body) {
        @SuppressWarnings("unchecked")
        Map<String, Object> formData = body != null ? (Map<String, Object>) body.get("form_data") : null;
        String userInputCode = body != null ? (String) body.get("user_input_code") : null;
        String code = numberingRuleService.allocateCode(ruleId, companyCode, formData, userInputCode);
        return ResponseEntity.ok(ApiResponse.success(Map.of("generatedCode", code), "코드 할당이 완료되었습니다."));
    }

    /** POST /{ruleId}/generate (deprecated) → allocateCode 위임 */
    @PostMapping("/{ruleId}/generate")
    public ResponseEntity<ApiResponse<Map<String, Object>>> generateCode(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable String ruleId) {
        String code = numberingRuleService.generateCode(ruleId, companyCode);
        return ResponseEntity.ok(ApiResponse.success(Map.of("generatedCode", code), "코드 생성이 완료되었습니다."));
    }

    /** admin 권한 (SUPER_ADMIN / ADMIN / COMPANY_ADMIN) 만 시퀀스 직접 조작 가능 */
    private boolean isAdminRole(String role) {
        return "SUPER_ADMIN".equals(role)
                || "ADMIN".equals(role)
                || "COMPANY_ADMIN".equals(role);
    }

    /** POST /{ruleId}/reset → 순번 초기화 (admin 전용) */
    @PostMapping("/{ruleId}/reset")
    public ResponseEntity<ApiResponse<Void>> resetSequence(
            @RequestAttribute("company_code") String companyCode,
            @RequestAttribute("role") String role,
            @PathVariable String ruleId) {
        if (!isAdminRole(role)) {
            return ResponseEntity.status(403)
                    .body(ApiResponse.error("관리자 권한이 필요합니다."));
        }
        numberingRuleService.resetSequence(ruleId, companyCode);
        return ResponseEntity.ok(ApiResponse.success(null, "시퀀스가 초기화되었습니다."));
    }

    /** PUT /{ruleId}/sequence → 현재 시퀀스 임의 값으로 수정 (admin 전용) */
    @PutMapping("/{ruleId}/sequence")
    public ResponseEntity<ApiResponse<Void>> updateRuleSequence(
            @RequestAttribute("company_code") String companyCode,
            @RequestAttribute("role") String role,
            @PathVariable String ruleId,
            @RequestBody Map<String, Object> body) {
        if (!isAdminRole(role)) {
            return ResponseEntity.status(403)
                    .body(ApiResponse.error("관리자 권한이 필요합니다."));
        }
        Object seqObj = body.get("sequence");
        if (seqObj == null) {
            return ResponseEntity.badRequest()
                    .body(ApiResponse.error("sequence 값이 필요합니다."));
        }
        Integer newSequence;
        try {
            newSequence = (seqObj instanceof Number)
                    ? ((Number) seqObj).intValue()
                    : Integer.parseInt(seqObj.toString());
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest()
                    .body(ApiResponse.error("sequence 는 정수여야 합니다."));
        }
        if (newSequence < 0) {
            return ResponseEntity.badRequest()
                    .body(ApiResponse.error("sequence 는 0 이상이어야 합니다."));
        }
        numberingRuleService.updateRuleSequence(ruleId, newSequence, companyCode);
        return ResponseEntity.ok(ApiResponse.success(null, "시퀀스가 수정되었습니다."));
    }

    // ================================================================
    // ■ Admin
    // ================================================================

    /** POST /copy-for-company → 회사간 규칙 복제 (SUPER_ADMIN) */
    @PostMapping("/copy-for-company")
    public ResponseEntity<ApiResponse<Map<String, Object>>> copyRulesForCompany(
            @RequestAttribute("company_code") String companyCode,
            @RequestBody Map<String, Object> body) {
        String sourceCompanyCode = (String) body.get("source_company_code");
        String targetCompanyCode = (String) body.get("target_company_code");
        if (sourceCompanyCode == null || targetCompanyCode == null) {
            return ResponseEntity.badRequest()
                    .body(ApiResponse.error("sourceCompanyCode와 targetCompanyCode가 필요합니다."));
        }
        Map<String, Object> result = numberingRuleService.copyRulesForCompany(
                sourceCompanyCode, targetCompanyCode);
        return ResponseEntity.ok(ApiResponse.success(result, "채번 규칙 복제가 완료되었습니다."));
    }
}
