package com.erp.provisioning;

import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

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

/**
 * 회사 관리 화면 라이프사이클 엔드포인트.
 *
 * 프로비저닝(생성) 은 {@link ProvisioningController} 가 담당. 이 컨트롤러는 그 이후의
 * 관리 액션 — 비활성/재활성/삭제, 관리자 계정 관리, 구성원 조회, 템플릿 재복제, 감사 로그.
 *
 * 전부 SUPER_ADMIN 전용 ({@link SuperAdminGuard}).
 */
@RestController
@RequestMapping("/api/admin/provisioning")
@RequiredArgsConstructor
@Slf4j
public class CompanyMgmtController {

    private final SuperAdminGuard guard;
    private final CompanyLifecycleService lifecycleService;
    private final CompanyAdminService adminService;
    private final CompanyMembersService membersService;
    private final CompanyTemplatesService templatesService;
    private final CompanyAuditLogService auditLogService;

    @Value("${spring.datasource.url}")
    private String metaJdbcUrl;

    // ─────────────── 관리자 계정 ───────────────

    @GetMapping("/companies/{companyCode}/admin")
    public ResponseEntity<Map<String, Object>> getAdmin(HttpServletRequest req, @PathVariable String companyCode) {
        guard.enforce(req);
        Map<String, Object> company = lifecycleService.getCompany(companyCode);
        if (company == null) return ResponseEntity.notFound().build();
        String dbName = (String) company.get("db_name");
        Map<String, Object> admin = adminService.getAdmin(dbName);
        admin.put("company_code", companyCode);
        admin.put("db_name", dbName);
        return ResponseEntity.ok(admin);
    }

    @PostMapping("/companies/{companyCode}/admin/reset-password")
    public ResponseEntity<Map<String, Object>> resetAdminPassword(HttpServletRequest req,
                                                                  @PathVariable String companyCode) {
        guard.enforce(req);
        Map<String, Object> company = lifecycleService.getCompany(companyCode);
        if (company == null) return ResponseEntity.notFound().build();
        String dbName = (String) company.get("db_name");
        Map<String, Object> result = adminService.resetAdminPassword(dbName);

        String actor = guard.actorUserId(req);
        if (result.containsKey("error")) {
            auditLogService.logFailure(companyCode, actor, CompanyAuditLogService.ACTION_PW_RESET,
                    dbName, Map.of("error_kind", result.get("error")), (String) result.get("error"));
            return ResponseEntity.status(500).body(result);
        }
        auditLogService.log(companyCode, actor, CompanyAuditLogService.ACTION_PW_RESET,
                (String) result.get("admin_user_id"), Map.of("db_name", dbName));
        return ResponseEntity.ok()
                .header("Cache-Control", "no-store")
                .header("Pragma", "no-cache")
                .body(result);
    }

    // ─────────────── 구성원 ───────────────

    @GetMapping("/companies/{companyCode}/members")
    public ResponseEntity<Map<String, Object>> listMembers(HttpServletRequest req,
                                                           @PathVariable String companyCode) {
        guard.enforce(req);
        Map<String, Object> company = lifecycleService.getCompany(companyCode);
        if (company == null) return ResponseEntity.notFound().build();
        String dbName = (String) company.get("db_name");
        List<Map<String, Object>> members = membersService.listMembers(dbName);
        Map<String, Object> out = new LinkedHashMap<>();
        out.put("company_code", companyCode);
        out.put("db_name", dbName);
        out.put("members", members);
        out.put("total", members.size());
        return ResponseEntity.ok(out);
    }

    // ─────────────── 템플릿 ───────────────

    @GetMapping("/companies/{companyCode}/installed-groups")
    public ResponseEntity<List<Map<String, Object>>> installedGroups(HttpServletRequest req,
                                                                     @PathVariable String companyCode) {
        guard.enforce(req);
        return ResponseEntity.ok(templatesService.listInstalledGroups(companyCode));
    }

    @PostMapping("/companies/{companyCode}/re-copy")
    public ResponseEntity<Map<String, Object>> recopyTemplates(HttpServletRequest req,
                                                               @PathVariable String companyCode,
                                                               @RequestBody Map<String, Object> body) {
        guard.enforce(req);
        Map<String, Object> company = lifecycleService.getCompany(companyCode);
        if (company == null) return ResponseEntity.notFound().build();
        String dstDb = (String) company.get("db_name");
        String srcDb = resolveMetaDbName();

        @SuppressWarnings("unchecked")
        List<String> groups = (List<String>) body.getOrDefault("selected_groups", List.of());
        if (groups.isEmpty()) {
            return ResponseEntity.badRequest().body(Map.of("error", "selected_groups required"));
        }

        Map<String, Object> result = templatesService.recopy(srcDb, dstDb, groups);
        String actor = guard.actorUserId(req);
        List<?> errors = (List<?>) result.get("errors");
        if (errors != null && !errors.isEmpty()) {
            auditLogService.logFailure(companyCode, actor, CompanyAuditLogService.ACTION_RECOPY,
                    dstDb, Map.of("selected_groups", groups, "errors", errors),
                    "partial_failure: " + errors.size() + " table(s)");
        } else {
            auditLogService.log(companyCode, actor, CompanyAuditLogService.ACTION_RECOPY, dstDb,
                    Map.of("selected_groups", groups, "total_inserted", result.get("total_inserted")));
        }
        return ResponseEntity.ok(result);
    }

    // ─────────────── 라이프사이클 ───────────────

    @PatchMapping("/companies/{companyCode}/status")
    public ResponseEntity<Map<String, Object>> changeStatus(HttpServletRequest req,
                                                            @PathVariable String companyCode,
                                                            @RequestBody Map<String, Object> body) {
        guard.enforce(req);
        String target = (String) body.get("status");
        String reason = (String) body.get("reason");
        if (target == null) {
            return ResponseEntity.badRequest().body(Map.of("error", "status required"));
        }
        String actor = guard.actorUserId(req);
        Map<String, Object> result;
        String action;
        if ("suspended".equals(target)) {
            result = lifecycleService.deactivate(companyCode, reason);
            action = CompanyAuditLogService.ACTION_DEACTIVATE;
        } else if ("active".equals(target)) {
            result = lifecycleService.reactivate(companyCode);
            action = CompanyAuditLogService.ACTION_REACTIVATE;
        } else {
            return ResponseEntity.badRequest().body(Map.of("error", "unsupported status: " + target));
        }
        if (result.containsKey("error")) {
            auditLogService.logFailure(companyCode, actor, action, null,
                    Map.of("target_status", target, "reason", reason == null ? "" : reason),
                    String.valueOf(result.get("error")));
            return ResponseEntity.badRequest().body(result);
        }
        auditLogService.log(companyCode, actor, action, (String) result.get("subdomain"),
                Map.of("target_status", target, "reason", reason == null ? "" : reason));
        return ResponseEntity.ok(result);
    }

    /**
     * 영구 삭제. 안전장치: 요청 본문에 {@code confirm_subdomain} 을 담아 보내야 함 (프론트 타이핑 확인).
     * 이 값이 현재 서브도메인과 정확히 일치해야 실행.
     */
    @DeleteMapping("/companies/{companyCode}")
    public ResponseEntity<Map<String, Object>> deleteCompany(HttpServletRequest req,
                                                             @PathVariable String companyCode,
                                                             @RequestBody(required = false) Map<String, Object> body) {
        guard.enforce(req);
        Map<String, Object> company = lifecycleService.getCompany(companyCode);
        if (company == null) return ResponseEntity.notFound().build();

        String currentSub = (String) company.get("subdomain");
        String confirmSub = body == null ? null : (String) body.get("confirm_subdomain");
        if (confirmSub == null || !confirmSub.equals(currentSub)) {
            return ResponseEntity.status(400).body(Map.of(
                    "error", "confirmation_mismatch",
                    "message", "confirm_subdomain 이 실제 서브도메인과 일치해야 함"));
        }

        String actor = guard.actorUserId(req);
        Map<String, Object> result = lifecycleService.delete(companyCode);

        auditLogService.log(companyCode, actor, CompanyAuditLogService.ACTION_DELETE,
                (String) result.get("db_name"),
                Map.of("subdomain", result.get("subdomain"),
                        "meta_rows_removed", result.get("meta_rows_removed")));
        return ResponseEntity.ok(result);
    }

    // ─────────────── 감사 로그 ───────────────

    @GetMapping("/companies/{companyCode}/audit-log")
    public ResponseEntity<Map<String, Object>> companyAuditLog(HttpServletRequest req,
                                                               @PathVariable String companyCode,
                                                               @RequestParam(defaultValue = "1") int page,
                                                               @RequestParam(defaultValue = "50") int limit) {
        guard.enforce(req);
        return ResponseEntity.ok(auditLogService.listByCompany(companyCode, page, limit));
    }

    @GetMapping("/audit-log")
    public ResponseEntity<Map<String, Object>> globalAuditLog(HttpServletRequest req,
                                                              @RequestParam(defaultValue = "1") int page,
                                                              @RequestParam(defaultValue = "50") int limit,
                                                              @RequestParam(required = false) String action) {
        guard.enforce(req);
        return ResponseEntity.ok(auditLogService.listAll(page, limit, action));
    }

    // ─────────────── helpers ───────────────

    /** jdbc:postgresql://host:port/{db_name}?... 에서 db_name 추출. */
    private String resolveMetaDbName() {
        int slash = metaJdbcUrl.lastIndexOf('/');
        if (slash < 0) return "invyone";
        String tail = metaJdbcUrl.substring(slash + 1);
        int q = tail.indexOf('?');
        return q < 0 ? tail : tail.substring(0, q);
    }
}
