package com.erp.controller;

import com.erp.dto.ApiResponse;
import com.erp.service.TableManagementService;
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/table-management")
@RequiredArgsConstructor
@Slf4j
public class TableManagementController {

    private final TableManagementService tableManagementService;

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

    /** GET /api/table-management/tables */
    @GetMapping("/tables")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTableList() {
        return ResponseEntity.ok(ApiResponse.success(
                tableManagementService.getTableList(), "테이블 목록을 성공적으로 조회했습니다."));
    }

    // ──────────────────────────────────────────────────────────
    // 엔티티 관계 (literal segment이 path variable보다 우선)
    // ──────────────────────────────────────────────────────────

    /** GET /api/table-management/tables/entity-relations */
    @GetMapping("/tables/entity-relations")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getTableEntityRelations(
            @RequestParam String leftTable,
            @RequestParam String rightTable,
            @RequestAttribute("company_code") String companyCode) {
        return ResponseEntity.ok(ApiResponse.success(
                tableManagementService.getTableEntityRelations(leftTable, rightTable, companyCode)));
    }

    // ──────────────────────────────────────────────────────────
    // 컬럼 목록
    // ──────────────────────────────────────────────────────────

    /** GET /api/table-management/tables/:tableName/columns */
    @GetMapping("/tables/{tableName}/columns")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getColumnList(
            @PathVariable String tableName,
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "50") int size,
            @RequestAttribute("company_code") String companyCode) {
        return ResponseEntity.ok(ApiResponse.success(
                tableManagementService.getColumnList(tableName, page, size, companyCode),
                "컬럼 목록을 성공적으로 조회했습니다."));
    }

    // ──────────────────────────────────────────────────────────
    // 테이블 라벨
    // ──────────────────────────────────────────────────────────

    /** GET /api/table-management/tables/:tableName/labels */
    @GetMapping("/tables/{tableName}/labels")
    public ResponseEntity<ApiResponse<Object>> getTableLabels(@PathVariable String tableName) {
        Map<String, Object> labels = tableManagementService.getTableLabels(tableName);
        Object data = labels != null ? labels : Map.of();
        return ResponseEntity.ok(ApiResponse.success(data, "테이블 라벨 정보를 조회했습니다."));
    }

    /** PUT /api/table-management/tables/:tableName/label */
    @PutMapping("/tables/{tableName}/label")
    public ResponseEntity<ApiResponse<Void>> updateTableLabel(
            @PathVariable String tableName,
            @RequestBody Map<String, Object> body,
            @RequestAttribute("role") String role) {
        if (!isAdmin(role)) {
            return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
        }
        String displayName = (String) body.get("display_name");
        String description = (String) body.get("description");
        if (displayName == null || displayName.isBlank()) {
            return ResponseEntity.status(400).body(ApiResponse.error("표시명이 필요합니다."));
        }
        tableManagementService.updateTableLabel(tableName, displayName, description);
        return ResponseEntity.ok(ApiResponse.success(null, "테이블 라벨이 성공적으로 설정되었습니다."));
    }

    // ──────────────────────────────────────────────────────────
    // 컬럼 설정
    // ──────────────────────────────────────────────────────────

    /** GET /api/table-management/tables/:tableName/columns/:columnName/labels */
    @GetMapping("/tables/{tableName}/columns/{columnName}/labels")
    public ResponseEntity<ApiResponse<Object>> getColumnLabels(
            @PathVariable String tableName,
            @PathVariable String columnName) {
        Map<String, Object> labels = tableManagementService.getColumnLabels(tableName, columnName);
        Object data = labels != null ? labels : Map.of();
        return ResponseEntity.ok(ApiResponse.success(data, "컬럼 라벨 정보를 조회했습니다."));
    }

    /** POST /api/table-management/tables/:tableName/columns/:columnName/settings */
    @PostMapping("/tables/{tableName}/columns/{columnName}/settings")
    public ResponseEntity<ApiResponse<Void>> updateColumnSettingsPost(
            @PathVariable String tableName,
            @PathVariable String columnName,
            @RequestBody Map<String, Object> settings,
            @RequestAttribute("role") String role,
            @RequestAttribute("company_code") String companyCode) {
        if (!isAdmin(role)) {
            return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
        }
        return doUpdateColumnSettings(tableName, columnName, settings, companyCode);
    }

    /** PUT /api/table-management/tables/:tableName/columns/:columnName */
    @PutMapping("/tables/{tableName}/columns/{columnName}")
    public ResponseEntity<ApiResponse<Void>> updateColumnSettingsPut(
            @PathVariable String tableName,
            @PathVariable String columnName,
            @RequestBody Map<String, Object> settings,
            @RequestAttribute("role") String role,
            @RequestAttribute("company_code") String companyCode) {
        if (!isAdmin(role)) {
            return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
        }
        return doUpdateColumnSettings(tableName, columnName, settings, companyCode);
    }

    private ResponseEntity<ApiResponse<Void>> doUpdateColumnSettings(
            String tableName, String columnName, Map<String, Object> settings, String companyCode) {
        if (tableName == null || columnName == null) {
            return ResponseEntity.status(400).body(ApiResponse.error("테이블명과 컬럼명이 필요합니다."));
        }
        if (settings == null) {
            return ResponseEntity.status(400).body(ApiResponse.error("컬럼 설정 정보가 필요합니다."));
        }
        tableManagementService.updateColumnSettings(tableName, columnName, settings, companyCode);
        return ResponseEntity.ok(ApiResponse.success(null, "컬럼 설정을 성공적으로 저장했습니다."));
    }

    /** POST /api/table-management/tables/:tableName/columns/settings (batch) */
    @PostMapping("/tables/{tableName}/columns/settings")
    public ResponseEntity<ApiResponse<Void>> updateAllColumnSettingsPost(
            @PathVariable String tableName,
            @RequestBody List<Map<String, Object>> columnSettings,
            @RequestAttribute("role") String role,
            @RequestAttribute("company_code") String companyCode) {
        if (!isAdmin(role)) {
            return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
        }
        return doUpdateAllColumnSettings(tableName, columnSettings, companyCode);
    }

    /** PUT /api/table-management/tables/:tableName/columns/batch */
    @PutMapping("/tables/{tableName}/columns/batch")
    public ResponseEntity<ApiResponse<Void>> updateAllColumnSettingsBatch(
            @PathVariable String tableName,
            @RequestBody List<Map<String, Object>> columnSettings,
            @RequestAttribute("role") String role,
            @RequestAttribute("company_code") String companyCode) {
        if (!isAdmin(role)) {
            return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
        }
        return doUpdateAllColumnSettings(tableName, columnSettings, companyCode);
    }

    private ResponseEntity<ApiResponse<Void>> doUpdateAllColumnSettings(
            String tableName, List<Map<String, Object>> columnSettings, String companyCode) {
        if (tableName == null) {
            return ResponseEntity.status(400).body(ApiResponse.error("테이블명이 필요합니다."));
        }
        if (columnSettings == null || columnSettings.isEmpty()) {
            return ResponseEntity.status(400).body(ApiResponse.error("컬럼 설정 목록이 필요합니다."));
        }
        tableManagementService.updateAllColumnSettings(tableName, columnSettings, companyCode);
        return ResponseEntity.ok(ApiResponse.success(null, "모든 컬럼 설정을 성공적으로 저장했습니다."));
    }

    /** PUT /api/table-management/tables/:tableName/columns/:columnName/web-type */
    @PutMapping("/tables/{tableName}/columns/{columnName}/web-type")
    public ResponseEntity<ApiResponse<Void>> updateColumnWebType(
            @PathVariable String tableName,
            @PathVariable String columnName,
            @RequestBody Map<String, Object> body,
            @RequestAttribute("role") String role,
            @RequestAttribute("company_code") String companyCode) {
        if (!isAdmin(role)) {
            return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
        }
        String webType = (String) body.get("web_type");
        if (webType == null || webType.isBlank()) {
            return ResponseEntity.status(400).body(ApiResponse.error("웹 타입이 필요합니다."));
        }
        @SuppressWarnings("unchecked")
        Map<String, Object> detailSettings = (Map<String, Object>) body.get("detail_settings");
        // 멀티테넌트 격리: SUPER_ADMIN(company_code='*') 가 아니면 자기 회사 코드로 저장
        tableManagementService.updateColumnWebType(tableName, columnName, webType, detailSettings, companyCode);
        return ResponseEntity.ok(ApiResponse.success(null, "컬럼 웹타입이 설정되었습니다."));
    }

    /** PUT /api/table-management/tables/:tableName/columns/:columnName/input-type */
    @PutMapping("/tables/{tableName}/columns/{columnName}/input-type")
    public ResponseEntity<ApiResponse<Void>> updateColumnInputType(
            @PathVariable String tableName,
            @PathVariable String columnName,
            @RequestBody Map<String, Object> body,
            @RequestAttribute("role") String role,
            @RequestAttribute("company_code") String companyCode) {
        if (!isAdmin(role)) {
            return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
        }
        String inputType = (String) body.get("input_type");
        if (tableName == null || columnName == null || inputType == null || inputType.isBlank()) {
            return ResponseEntity.status(400).body(ApiResponse.error("테이블명, 컬럼명, 입력 타입이 모두 필요합니다."));
        }
        @SuppressWarnings("unchecked")
        Map<String, Object> detailSettings = (Map<String, Object>) body.get("detail_settings");
        tableManagementService.updateColumnInputType(tableName, columnName, inputType, companyCode, detailSettings);
        return ResponseEntity.ok(ApiResponse.success(null, "컬럼 입력 타입이 성공적으로 설정되었습니다."));
    }

    // ──────────────────────────────────────────────────────────
    // 테이블 스키마 / 존재 여부 / 웹타입
    // ──────────────────────────────────────────────────────────

    /** GET /api/table-management/tables/:tableName/schema */
    @GetMapping("/tables/{tableName}/schema")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTableSchema(
            @PathVariable String tableName) {
        return ResponseEntity.ok(ApiResponse.success(
                tableManagementService.getTableSchema(tableName),
                "테이블 스키마 정보를 성공적으로 조회했습니다."));
    }

    /** GET /api/table-management/tables/:tableName/exists */
    @GetMapping("/tables/{tableName}/exists")
    public ResponseEntity<ApiResponse<Map<String, Object>>> checkTableExists(
            @PathVariable String tableName) {
        boolean exists = tableManagementService.checkTableExists(tableName);
        return ResponseEntity.ok(ApiResponse.success(Map.of("exists", exists), "테이블 존재 여부를 확인했습니다."));
    }

    /** GET /api/table-management/tables/:tableName/web-types */
    @GetMapping("/tables/{tableName}/web-types")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getColumnWebTypes(
            @PathVariable String tableName,
            @RequestAttribute("company_code") String companyCode) {
        return ResponseEntity.ok(ApiResponse.success(
                tableManagementService.getColumnInputTypes(tableName, companyCode),
                "컬럼 입력타입 정보를 성공적으로 조회했습니다."));
    }

    // ──────────────────────────────────────────────────────────
    // 제약조건 관리
    // ──────────────────────────────────────────────────────────

    /** GET /api/table-management/tables/:tableName/constraints */
    @GetMapping("/tables/{tableName}/constraints")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getTableConstraints(
            @PathVariable String tableName) {
        return ResponseEntity.ok(ApiResponse.success(
                tableManagementService.getTableConstraints(tableName)));
    }

    /** PUT /api/table-management/tables/:tableName/primary-key */
    @PutMapping("/tables/{tableName}/primary-key")
    public ResponseEntity<ApiResponse<Void>> setTablePrimaryKey(
            @PathVariable String tableName,
            @RequestBody Map<String, Object> body,
            @RequestAttribute("role") String role) {
        if (!isSuperAdmin(role)) {
            return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자(SUPER_ADMIN) 권한이 필요합니다."));
        }
        @SuppressWarnings("unchecked")
        List<String> columns = (List<String>) body.get("columns");
        if (tableName == null || columns == null || columns.isEmpty()) {
            return ResponseEntity.status(400).body(ApiResponse.error("테이블명과 PK 컬럼 배열이 필요합니다."));
        }
        tableManagementService.setTablePrimaryKey(tableName, columns);
        return ResponseEntity.ok(ApiResponse.success(null,
                "PK가 설정되었습니다: " + String.join(", ", columns)));
    }

    /** POST /api/table-management/tables/:tableName/indexes */
    @PostMapping("/tables/{tableName}/indexes")
    public ResponseEntity<ApiResponse<Void>> toggleTableIndex(
            @PathVariable String tableName,
            @RequestBody Map<String, Object> body,
            @RequestAttribute("role") String role) {
        if (!isSuperAdmin(role)) {
            return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자(SUPER_ADMIN) 권한이 필요합니다."));
        }
        String columnName = (String) body.get("column_name");
        String indexType = (String) body.get("index_type");
        String action = (String) body.get("action");
        if (tableName == null || columnName == null || indexType == null || action == null) {
            return ResponseEntity.status(400).body(ApiResponse.error(
                    "tableName, columnName, indexType(index|unique), action(create|drop)이 필요합니다."));
        }
        try {
            tableManagementService.toggleTableIndex(tableName, columnName, indexType, action);
            String msg = "create".equals(action)
                    ? "인덱스가 생성되었습니다."
                    : "인덱스가 삭제되었습니다.";
            return ResponseEntity.ok(ApiResponse.success(null, msg));
        } catch (Exception e) {
            return ResponseEntity.status(500).body(ApiResponse.error(e.getMessage()));
        }
    }

    /** PUT /api/table-management/tables/:tableName/columns/:columnName/nullable */
    @PutMapping("/tables/{tableName}/columns/{columnName}/nullable")
    public ResponseEntity<ApiResponse<Void>> toggleColumnNullable(
            @PathVariable String tableName,
            @PathVariable String columnName,
            @RequestBody Map<String, Object> body,
            @RequestAttribute("role") String role,
            @RequestAttribute("company_code") String companyCode) {
        if (!isSuperAdmin(role)) {
            return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자(SUPER_ADMIN) 권한이 필요합니다."));
        }
        Object nullableObj = body.get("nullable");
        if (tableName == null || columnName == null || !(nullableObj instanceof Boolean)) {
            return ResponseEntity.status(400).body(ApiResponse.error("tableName, columnName, nullable(boolean)이 필요합니다."));
        }
        boolean nullable = (Boolean) nullableObj;
        tableManagementService.toggleColumnNullable(tableName, columnName, nullable, companyCode);
        String msg = nullable ? columnName + " 컬럼의 NOT NULL 제약이 해제되었습니다."
                : columnName + " 컬럼이 NOT NULL로 설정되었습니다.";
        return ResponseEntity.ok(ApiResponse.success(null, msg));
    }

    /** PUT /api/table-management/tables/:tableName/columns/:columnName/unique */
    @PutMapping("/tables/{tableName}/columns/{columnName}/unique")
    public ResponseEntity<ApiResponse<Void>> toggleColumnUnique(
            @PathVariable String tableName,
            @PathVariable String columnName,
            @RequestBody Map<String, Object> body,
            @RequestAttribute("role") String role,
            @RequestAttribute("company_code") String companyCode) {
        if (!isSuperAdmin(role)) {
            return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자(SUPER_ADMIN) 권한이 필요합니다."));
        }
        Object uniqueObj = body.get("unique");
        if (tableName == null || columnName == null || !(uniqueObj instanceof Boolean)) {
            return ResponseEntity.status(400).body(ApiResponse.error("tableName, columnName, unique(boolean)이 필요합니다."));
        }
        boolean unique = (Boolean) uniqueObj;
        tableManagementService.toggleColumnUnique(tableName, columnName, unique, companyCode);
        String msg = unique ? columnName + " 컬럼이 UNIQUE로 설정되었습니다."
                : columnName + " 컬럼의 UNIQUE 제약이 해제되었습니다.";
        return ResponseEntity.ok(ApiResponse.success(null, msg));
    }

    // ──────────────────────────────────────────────────────────
    // 데이터 CRUD
    // ──────────────────────────────────────────────────────────

    /** POST /api/table-management/tables/:tableName/data */
    @PostMapping("/tables/{tableName}/data")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getTableData(
            @PathVariable String tableName,
            @RequestBody Map<String, Object> options) {
        return ResponseEntity.ok(ApiResponse.success(
                tableManagementService.getTableData(tableName, options),
                "테이블 데이터를 성공적으로 조회했습니다."));
    }

    /** POST /api/table-management/tables/:tableName/aggregate
     *  body: { aggregation: "count"|"sum"|..., columnName?: string, filters?: [...] }
     *  → { value: number }
     */
    @PostMapping("/tables/{tableName}/aggregate")
    public ResponseEntity<ApiResponse<Map<String, Object>>> aggregateTableData(
            @PathVariable String tableName,
            @RequestBody Map<String, Object> options) {
        try {
            return ResponseEntity.ok(ApiResponse.success(
                    tableManagementService.aggregateTableData(tableName, options == null ? Map.of() : options),
                    "테이블 집계를 성공적으로 조회했습니다."));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
        }
    }

    /** POST /api/table-management/tables/:tableName/aggregate-group
     *  body: { aggregation, groupBy, valueColumn?, filters?, limit?, orderDir? }
     *  → { rows: [{ group, value }, ...] }
     */
    @PostMapping("/tables/{tableName}/aggregate-group")
    public ResponseEntity<ApiResponse<Map<String, Object>>> aggregateTableGroup(
            @PathVariable String tableName,
            @RequestBody Map<String, Object> options) {
        try {
            return ResponseEntity.ok(ApiResponse.success(
                    tableManagementService.aggregateTableGroup(tableName, options == null ? Map.of() : options),
                    "테이블 그룹 집계를 성공적으로 조회했습니다."));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
        }
    }

    /** POST /api/table-management/tables/:tableName/select-rows
     *  body: { columns?, filters?, orderBy?, limit?, offset? }
     *  → { rows: [{...}, ...] }
     */
    @PostMapping("/tables/{tableName}/select-rows")
    public ResponseEntity<ApiResponse<Map<String, Object>>> selectTableRows(
            @PathVariable String tableName,
            @RequestBody Map<String, Object> options) {
        try {
            return ResponseEntity.ok(ApiResponse.success(
                    tableManagementService.selectTableRows(tableName, options == null ? Map.of() : options),
                    "테이블 row 를 성공적으로 조회했습니다."));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
        }
    }

    /** POST /api/table-management/tables/:tableName/record (단일 레코드) */
    @PostMapping("/tables/{tableName}/record")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getTableRecord(
            @PathVariable String tableName,
            @RequestBody Map<String, Object> body) {
        String filterColumn = (String) body.get("filter_column");
        Object filterValue = body.get("filter_value");
        String displayColumn = (String) body.get("display_column");

        if (filterColumn == null || filterValue == null) {
            return ResponseEntity.status(400).body(ApiResponse.error(
                    "tableName, filterColumn, filterValue가 필요합니다."));
        }

        Map<String, Object> options = new java.util.HashMap<>();
        options.put("page", 1);
        options.put("size", 1);
        options.put("search", Map.of(filterColumn, filterValue.toString()));

        Map<String, Object> result = tableManagementService.getTableData(tableName, options);
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> data = (List<Map<String, Object>>) result.get("data");

        if (data == null || data.isEmpty()) {
            return ResponseEntity.status(404).body(ApiResponse.error("데이터를 찾을 수 없습니다."));
        }

        Map<String, Object> record = data.get(0);
        Object displayValue = (displayColumn != null && !displayColumn.equals("*"))
                ? record.get(displayColumn) : record;

        return ResponseEntity.ok(ApiResponse.success(
                Map.of("value", displayValue != null ? displayValue : "", "record", record),
                "레코드를 성공적으로 조회했습니다."));
    }

    /** POST /api/table-management/tables/:tableName/add */
    @PostMapping("/tables/{tableName}/add")
    public ResponseEntity<ApiResponse<Map<String, Object>>> addTableData(
            @PathVariable String tableName,
            @RequestBody Map<String, Object> data,
            @RequestAttribute("role") String role,
            @RequestAttribute("company_code") String companyCode) {
        if (!isAdmin(role)) {
            return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
        }
        if (data == null || data.isEmpty()) {
            return ResponseEntity.status(400).body(ApiResponse.error("추가할 데이터가 필요합니다."));
        }

        // 멀티테넌시: company_code 자동 추가
        if (!data.containsKey("company_code") && tableManagementService.hasColumn(tableName, "company_code")) {
            data.put("company_code", companyCode);
        }

        // 소프트 제약조건 검증
        List<String> notNullViolations = tableManagementService.validateNotNullConstraints(tableName, data, companyCode);
        if (!notNullViolations.isEmpty()) {
            return ResponseEntity.status(400).body(ApiResponse.error(
                    "필수 항목이 비어있습니다: " + String.join(", ", notNullViolations)));
        }
        List<String> uniqueViolations = tableManagementService.validateUniqueConstraints(tableName, data, companyCode, null);
        if (!uniqueViolations.isEmpty()) {
            return ResponseEntity.status(400).body(ApiResponse.error(
                    "중복된 값이 존재합니다: " + String.join(", ", uniqueViolations)));
        }

        Map<String, Object> result = tableManagementService.addTableData(tableName, data);
        return ResponseEntity.status(201).body(ApiResponse.success(
                Map.of("id", result.getOrDefault("inserted_id", "")),
                "테이블 데이터를 성공적으로 추가했습니다."));
    }

    /** PUT /api/table-management/tables/:tableName/edit */
    @PutMapping("/tables/{tableName}/edit")
    public ResponseEntity<ApiResponse<Void>> editTableData(
            @PathVariable String tableName,
            @RequestBody Map<String, Object> body,
            @RequestAttribute("role") String role,
            @RequestAttribute("company_code") String companyCode) {
        if (!isAdmin(role)) {
            return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
        }
        @SuppressWarnings("unchecked")
        Map<String, Object> originalData = (Map<String, Object>) body.get("original_data");
        @SuppressWarnings("unchecked")
        Map<String, Object> updatedData = (Map<String, Object>) body.get("updated_data");

        if (originalData == null || updatedData == null) {
            return ResponseEntity.status(400).body(ApiResponse.error("원본 데이터와 수정할 데이터가 모두 필요합니다."));
        }
        if (updatedData.isEmpty()) {
            return ResponseEntity.status(400).body(ApiResponse.error("수정할 데이터가 없습니다."));
        }

        // 소프트 제약조건 검증
        List<String> notNullViolations = tableManagementService.validateNotNullConstraints(tableName, updatedData, companyCode);
        if (!notNullViolations.isEmpty()) {
            return ResponseEntity.status(400).body(ApiResponse.error(
                    "필수 항목이 비어있습니다: " + String.join(", ", notNullViolations)));
        }
        String excludeId = originalData.get("id") != null ? originalData.get("id").toString() : null;
        List<String> uniqueViolations = tableManagementService.validateUniqueConstraints(tableName, updatedData, companyCode, excludeId);
        if (!uniqueViolations.isEmpty()) {
            return ResponseEntity.status(400).body(ApiResponse.error(
                    "중복된 값이 존재합니다: " + String.join(", ", uniqueViolations)));
        }

        tableManagementService.editTableData(tableName, originalData, updatedData);
        return ResponseEntity.ok(ApiResponse.success(null, "테이블 데이터를 성공적으로 수정했습니다."));
    }

    /** DELETE /api/table-management/tables/:tableName/delete */
    @DeleteMapping("/tables/{tableName}/delete")
    public ResponseEntity<ApiResponse<Void>> deleteTableData(
            @PathVariable String tableName,
            @RequestBody Object body,
            @RequestAttribute("role") String role) {
        if (!isAdmin(role)) {
            return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
        }
        List<Map<String, Object>> dataList;
        if (body instanceof List) {
            @SuppressWarnings("unchecked")
            List<Map<String, Object>> cast = (List<Map<String, Object>>) body;
            dataList = cast;
        } else {
            return ResponseEntity.status(400).body(ApiResponse.error("삭제할 데이터가 필요합니다."));
        }
        if (dataList.isEmpty()) {
            return ResponseEntity.status(400).body(ApiResponse.error("삭제할 데이터가 필요합니다."));
        }
        tableManagementService.deleteTableData(tableName, dataList);
        return ResponseEntity.ok(ApiResponse.success(null, "테이블 데이터를 성공적으로 삭제했습니다."));
    }

    // ──────────────────────────────────────────────────────────
    // 로그 관리
    // ──────────────────────────────────────────────────────────

    /** POST /api/table-management/tables/:tableName/log */
    @PostMapping("/tables/{tableName}/log")
    public ResponseEntity<ApiResponse<Void>> createLogTable(
            @PathVariable String tableName,
            @RequestBody Map<String, Object> body,
            @RequestAttribute("role") String role) {
        if (!isSuperAdmin(role)) {
            return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자(SUPER_ADMIN) 권한이 필요합니다."));
        }
        @SuppressWarnings("unchecked")
        List<String> logColumns = (List<String>) body.get("log_columns");
        boolean isActive = Boolean.TRUE.equals(body.get("is_active"));
        tableManagementService.createLogTable(tableName, logColumns, isActive);
        return ResponseEntity.ok(ApiResponse.success(null, "로그 테이블이 생성되었습니다."));
    }

    /** GET /api/table-management/tables/:tableName/log/config */
    @GetMapping("/tables/{tableName}/log/config")
    public ResponseEntity<ApiResponse<Object>> getLogConfig(@PathVariable String tableName) {
        Map<String, Object> config = tableManagementService.getLogConfig(tableName);
        Object data = config != null ? config : Map.of();
        return ResponseEntity.ok(ApiResponse.success(data));
    }

    /** GET /api/table-management/tables/:tableName/log */
    @GetMapping("/tables/{tableName}/log")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getLogData(
            @PathVariable String tableName,
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "50") int size) {
        return ResponseEntity.ok(ApiResponse.success(
                tableManagementService.getLogData(tableName, page, size)));
    }

    /** POST /api/table-management/tables/:tableName/log/toggle */
    @PostMapping("/tables/{tableName}/log/toggle")
    public ResponseEntity<ApiResponse<Void>> toggleLogTable(
            @PathVariable String tableName,
            @RequestBody Map<String, Object> body,
            @RequestAttribute("role") String role) {
        if (!isAdmin(role)) {
            return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
        }
        boolean isActive = Boolean.TRUE.equals(body.get("is_active"));
        tableManagementService.toggleLogTable(tableName, isActive);
        return ResponseEntity.ok(ApiResponse.success(null,
                isActive ? "로그가 활성화되었습니다." : "로그가 비활성화되었습니다."));
    }

    // ──────────────────────────────────────────────────────────
    // 카테고리 / 채번 컬럼
    // ──────────────────────────────────────────────────────────

    /** GET /api/table-management/category-columns */
    @GetMapping("/category-columns")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCategoryColumnsByCompany(
            @RequestAttribute("company_code") String companyCode) {
        return ResponseEntity.ok(ApiResponse.success(
                tableManagementService.getCategoryColumnsByCompany(companyCode)));
    }

    /** GET /api/table-management/numbering-columns */
    @GetMapping("/numbering-columns")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getNumberingColumnsByCompany(
            @RequestAttribute("company_code") String companyCode) {
        return ResponseEntity.ok(ApiResponse.success(
                tableManagementService.getNumberingColumnsByCompany(companyCode)));
    }

    /** GET /api/table-management/menu/:menuObjid/category-columns */
    @GetMapping("/menu/{menuObjid}/category-columns")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCategoryColumnsByMenu(
            @PathVariable String menuObjid,
            @RequestAttribute("company_code") String companyCode) {
        return ResponseEntity.ok(ApiResponse.success(
                tableManagementService.getCategoryColumnsByMenu(companyCode, menuObjid)));
    }

    // ──────────────────────────────────────────────────────────
    // 현재 테이블을 참조하는 테이블
    // ──────────────────────────────────────────────────────────

    /** GET /api/table-management/columns/:tableName/referenced-by */
    @GetMapping("/columns/{tableName}/referenced-by")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getReferencedByTables(
            @PathVariable String tableName,
            @RequestAttribute("company_code") String companyCode) {
        return ResponseEntity.ok(ApiResponse.success(
                tableManagementService.getReferencedByTables(tableName, companyCode)));
    }

    // ──────────────────────────────────────────────────────────
    // 다중 테이블 저장 / 엑셀 검증
    // ──────────────────────────────────────────────────────────

    /** POST /api/table-management/multi-table-save */
    @PostMapping("/multi-table-save")
    public ResponseEntity<ApiResponse<Map<String, Object>>> multiTableSave(
            @RequestBody Map<String, Object> payload,
            @RequestAttribute("role") String role,
            @RequestAttribute("company_code") String companyCode) {
        if (!isAdmin(role)) {
            return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
        }
        return ResponseEntity.ok(ApiResponse.success(
                tableManagementService.multiTableSave(payload, companyCode),
                "다중 테이블 저장이 완료되었습니다."));
    }

    /** POST /api/table-management/validate-excel */
    @PostMapping("/validate-excel")
    public ResponseEntity<ApiResponse<Map<String, Object>>> validateExcelData(
            @RequestBody Map<String, Object> body,
            @RequestAttribute("company_code") String companyCode) {
        String tableName = (String) body.get("table_name");
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> rows = (List<Map<String, Object>>) body.get("rows");
        if (tableName == null || rows == null) {
            return ResponseEntity.status(400).body(ApiResponse.error("tableName과 rows가 필요합니다."));
        }
        return ResponseEntity.ok(ApiResponse.success(
                tableManagementService.validateExcelData(tableName, rows, companyCode)));
    }

    // ──────────────────────────────────────────────────────────
    // DB 헬스체크
    // ──────────────────────────────────────────────────────────

    /** GET /api/table-management/health */
    @GetMapping("/health")
    public ResponseEntity<ApiResponse<Map<String, Object>>> checkDatabaseConnection() {
        return ResponseEntity.ok(ApiResponse.success(
                tableManagementService.checkDatabaseConnection(), "데이터베이스 연결 상태를 확인했습니다."));
    }

    // ──────────────────────────────────────────────────────────
    // 권한 헬퍼
    // ──────────────────────────────────────────────────────────

    private boolean isAdmin(String role) {
        return isSuperAdmin(role) || "COMPANY_ADMIN".equals(role);
    }

    private boolean isSuperAdmin(String roleOrCode) {
        return "*".equals(roleOrCode) || "SUPER_ADMIN".equals(roleOrCode);
    }
}
