package com.erp.crosstenant;

import com.erp.dto.ApiResponse;
import com.erp.provisioning.CompanyAuditLogService;
import com.erp.service.AdminService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

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

/**
 * SUPER_ADMIN 의 cross-tenant USER WRITE 엔드포인트.
 *
 * 기본 패턴:
 *   1. {@link CrossTenantContext#isSuperAdmin} + {@link CrossTenantContext#isMetaContext} 가드
 *   2. 요청 body/path/query 에서 target {@code company_code} 추출 (필수)
 *   3. {@link CrossTenantExecutor#runInCompany} 로 그 회사 DB 컨텍스트 임시 전환
 *   4. 기존 {@link AdminService} 의 user write 메서드 호출 (재사용)
 *   5. finally 에서 컨텍스트 복원
 *
 * 기존 {@code POST /api/admin/users} 등 단일 회사 모드 엔드포인트는 무수정 — 회사 도메인
 * 컨텍스트에서 그대로 동작.
 *
 * @see CrossTenantExecutor
 * @see com.erp.controller.AdminController  // 단일 회사 모드 원본
 */
@RestController
@RequestMapping("/api/admin/cross-tenant/users")
@RequiredArgsConstructor
@Slf4j
public class CrossTenantUserController {

    private final CrossTenantExecutor executor;
    private final AdminService adminService;
    private final CompanyAuditLogService auditLogService;

    // ── 등록 / 수정 ─────────────────────────────────────────────────────

    /**
     * POST /api/admin/cross-tenant/users
     * SUPER_ADMIN 이 특정 회사 사용자 등록/수정 (회사는 body.company_code 로 명시).
     */
    @PostMapping
    public ResponseEntity<ApiResponse<Map<String, Object>>> saveUser(
            HttpServletRequest request,
            @RequestBody Map<String, Object> body) {
        ResponseEntity<ApiResponse<Map<String, Object>>> guard = guard(request);
        if (guard != null) return guard;

        String targetCompanyCode = (String) body.get("company_code");
        String actorId = (String) request.getAttribute("user_id");
        try {
            Map<String, Object> result = executor.runInCompany(targetCompanyCode,
                    () -> adminService.saveUser(body));
            auditLogService.log(targetCompanyCode, actorId,
                    CompanyAuditLogService.ACTION_CT_USER_CREATE,
                    (String) body.get("user_id"),
                    auditDetails(request, (String) body.get("user_id")));
            return ResponseEntity.ok(ApiResponse.success(result, "사용자 저장 성공"));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
        }
    }

    /**
     * POST /api/admin/cross-tenant/users/with-dept
     * 사원+부서 통합 저장 (cross-tenant).
     */
    @PostMapping("/with-dept")
    public ResponseEntity<ApiResponse<Map<String, Object>>> saveUserWithDept(
            HttpServletRequest request,
            @RequestBody Map<String, Object> body) {
        ResponseEntity<ApiResponse<Map<String, Object>>> guard = guard(request);
        if (guard != null) return guard;

        String targetCompanyCode = (String) body.get("company_code");
        try {
            Map<String, Object> result = executor.runInCompany(targetCompanyCode,
                    () -> adminService.saveUserWithDept(body));
            return ResponseEntity.ok(ApiResponse.success(result, "사원+부서 저장 성공"));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
        }
    }

    /**
     * PUT /api/admin/cross-tenant/users/{userId}
     * 사용자 수정 (REST). target company_code 는 body 에 명시.
     */
    @PutMapping("/{userId}")
    public ResponseEntity<ApiResponse<Map<String, Object>>> updateUser(
            HttpServletRequest request,
            @PathVariable String userId,
            @RequestBody Map<String, Object> body) {
        ResponseEntity<ApiResponse<Map<String, Object>>> guard = guard(request);
        if (guard != null) return guard;

        String targetCompanyCode = (String) body.get("company_code");
        body.put("user_id", userId);
        try {
            Map<String, Object> result = executor.runInCompany(targetCompanyCode,
                    () -> adminService.saveUser(body));
            return ResponseEntity.ok(ApiResponse.success(result, "사용자 수정 성공"));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
        }
    }

    /**
     * DELETE /api/admin/cross-tenant/users/{userId}?company_code=TEST01
     * 사용자 삭제 (비활성화). target company_code 는 query param.
     */
    @DeleteMapping("/{userId}")
    public ResponseEntity<ApiResponse<Void>> deleteUser(
            HttpServletRequest request,
            @PathVariable String userId,
            @RequestParam("company_code") String companyCode) {
        ResponseEntity<ApiResponse<Void>> guard = guardVoid(request);
        if (guard != null) return guard;

        String actorId = (String) request.getAttribute("user_id");
        try {
            executor.runInCompany(companyCode, () -> {
                Map<String, Object> existing = adminService.getUserInfo(userId);
                if (existing == null) {
                    throw new IllegalArgumentException("사용자를 찾을 수 없습니다: " + userId);
                }
                adminService.changeUserStatus(userId, "inactive");
            });
            auditLogService.log(companyCode, actorId,
                    CompanyAuditLogService.ACTION_CT_USER_DELETE,
                    userId,
                    auditDetails(request, userId));
            return ResponseEntity.ok(ApiResponse.success(null, "사용자 삭제 성공"));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.error(e.getMessage()));
        }
    }

    /**
     * PATCH /api/admin/cross-tenant/users/{userId}/status
     * 사용자 상태 변경. body: { "status": "active|inactive", "company_code": "TEST01" }
     */
    @PatchMapping("/{userId}/status")
    public ResponseEntity<ApiResponse<Void>> changeUserStatus(
            HttpServletRequest request,
            @PathVariable String userId,
            @RequestBody Map<String, Object> body) {
        ResponseEntity<ApiResponse<Void>> guard = guardVoid(request);
        if (guard != null) return guard;

        String targetCompanyCode = (String) body.get("company_code");
        String status = (String) body.get("status");
        try {
            executor.runInCompany(targetCompanyCode, () ->
                    adminService.changeUserStatus(userId, status));
            return ResponseEntity.ok(ApiResponse.success(null, "사용자 상태 변경 성공"));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.error(e.getMessage()));
        }
    }

    /**
     * POST /api/admin/cross-tenant/users/reset-password
     * body: { "user_id": "...", "company_code": "TEST01" }
     */
    @PostMapping("/reset-password")
    public ResponseEntity<ApiResponse<Void>> resetUserPassword(
            HttpServletRequest request,
            @RequestBody Map<String, Object> body) {
        ResponseEntity<ApiResponse<Void>> guard = guardVoid(request);
        if (guard != null) return guard;

        String targetCompanyCode = (String) body.get("company_code");
        String userId = (String) body.get("user_id");
        String actorId = (String) request.getAttribute("user_id");
        try {
            executor.runInCompany(targetCompanyCode, () ->
                    adminService.resetUserPassword(userId));
            auditLogService.log(targetCompanyCode, actorId,
                    CompanyAuditLogService.ACTION_CT_PW_RESET,
                    userId,
                    auditDetails(request, userId));
            return ResponseEntity.ok(ApiResponse.success(null, "비밀번호 초기화 성공"));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.error(e.getMessage()));
        }
    }

    // ── READ 보강 (단건 조회 / 중복확인 / 이력) ───────────────────────

    /**
     * GET /api/admin/cross-tenant/users/{userId}?company_code=TEST01
     * 단건 조회 — 회사 컨텍스트로 가서 USER_INFO 단건.
     */
    @GetMapping("/{userId}")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getUserInfo(
            HttpServletRequest request,
            @PathVariable String userId,
            @RequestParam("company_code") String companyCode) {
        ResponseEntity<ApiResponse<Map<String, Object>>> guard = guard(request);
        if (guard != null) return guard;

        try {
            Map<String, Object> info = executor.runInCompany(companyCode,
                    () -> adminService.getUserInfo(userId));
            if (info == null) {
                return ResponseEntity.status(HttpStatus.NOT_FOUND)
                        .body(ApiResponse.error("사용자를 찾을 수 없습니다."));
            }
            return ResponseEntity.ok(ApiResponse.success(info));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
        }
    }

    /**
     * GET /api/admin/cross-tenant/users/{userId}/with-dept?company_code=TEST01
     */
    @GetMapping("/{userId}/with-dept")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getUserWithDept(
            HttpServletRequest request,
            @PathVariable String userId,
            @RequestParam("company_code") String companyCode) {
        ResponseEntity<ApiResponse<Map<String, Object>>> guard = guard(request);
        if (guard != null) return guard;

        try {
            Map<String, Object> result = executor.runInCompany(companyCode, () -> {
                Map<String, Object> p = new HashMap<>();
                p.put("company_code", companyCode);
                p.put("user_id", userId);
                return adminService.getUserWithDept(p);
            });
            if (result == null) {
                return ResponseEntity.status(HttpStatus.NOT_FOUND)
                        .body(ApiResponse.error("사용자를 찾을 수 없습니다."));
            }
            return ResponseEntity.ok(ApiResponse.success(result));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
        }
    }

    /**
     * POST /api/admin/cross-tenant/users/check-duplicate
     * body: { "user_id": "...", "company_code": "TEST01" }
     */
    @PostMapping("/check-duplicate")
    public ResponseEntity<ApiResponse<Map<String, Object>>> checkDuplicateUserId(
            HttpServletRequest request,
            @RequestBody Map<String, Object> body) {
        ResponseEntity<ApiResponse<Map<String, Object>>> guard = guard(request);
        if (guard != null) return guard;

        String targetCompanyCode = (String) body.get("company_code");
        String userId = (String) body.get("user_id");
        try {
            Map<String, Object> result = executor.runInCompany(targetCompanyCode, () -> {
                Map<String, Object> existing = adminService.getUserInfo(userId);
                Map<String, Object> out = new HashMap<>();
                out.put("is_duplicate", existing != null);
                return out;
            });
            return ResponseEntity.ok(ApiResponse.success(result, "아이디 중복 확인 완료"));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
        }
    }

    // ── 가드 헬퍼 ───────────────────────────────────────────────────

    /** Map<String,Object> 응답용 가드 — null 이면 통과, 아니면 그대로 반환. */
    private ResponseEntity<ApiResponse<Map<String, Object>>> guard(HttpServletRequest request) {
        try {
            CrossTenantContext.requireManagementHost(request);
        } catch (org.springframework.web.server.ResponseStatusException e) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN)
                    .body(ApiResponse.error(e.getReason(), request.getRequestURI()));
        }
        if (!CrossTenantContext.isSuperAdmin(request)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN)
                    .body(ApiResponse.error("super_admin_required", request.getRequestURI()));
        }
        if (!CrossTenantContext.isMetaContext()) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                    .body(ApiResponse.error("cross_tenant_requires_meta_context", request.getRequestURI()));
        }
        return null;
    }

    /** Void 응답용 가드 (제네릭만 다름). */
    private ResponseEntity<ApiResponse<Void>> guardVoid(HttpServletRequest request) {
        try {
            CrossTenantContext.requireManagementHost(request);
        } catch (org.springframework.web.server.ResponseStatusException e) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN)
                    .body(ApiResponse.error(e.getReason(), request.getRequestURI()));
        }
        if (!CrossTenantContext.isSuperAdmin(request)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN)
                    .body(ApiResponse.error("super_admin_required", request.getRequestURI()));
        }
        if (!CrossTenantContext.isMetaContext()) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                    .body(ApiResponse.error("cross_tenant_requires_meta_context", request.getRequestURI()));
        }
        return null;
    }

    /** audit log details 기본 맵 생성 헬퍼. */
    private Map<String, Object> auditDetails(HttpServletRequest request, String targetUserId) {
        Map<String, Object> d = new HashMap<>();
        d.put("host", request.getHeader("Host"));
        if (targetUserId != null) d.put("target_user_id", targetUserId);
        return d;
    }
}
