package com.zioinfo.kintex.visitor;

import com.zioinfo.kintex.auth.EventAccessGuard;
import com.zioinfo.kintex.auth.EventRole;
import com.zioinfo.kintex.auth.KintexPrincipal;
import com.zioinfo.kintex.common.ApiResponse;
import com.zioinfo.kintex.common.PageResponse;
import com.zioinfo.kintex.common.audit.Audited;
import com.zioinfo.kintex.visitor.dto.VisitorDtos.*;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * M10 관람객·리드 API (SCR-30·SCR-32) + 공개 사전등록 접수.
 * <ul>
 *   <li>공개(비인증): {@code POST /api/public/events/{eventId}/register} — /api/public/** permitAll.</li>
 *   <li>인증: 요약·목록·리드 — {@link EventAccessGuard} 행사 접근 가드. 응답은 마스킹 필드만(PII 불변).</li>
 * </ul>
 */
@RestController
public class VisitorController {

    private final VisitorService service;
    private final EventAccessGuard guard;

    public VisitorController(VisitorService service, EventAccessGuard guard) {
        this.service = service;
        this.guard = guard;
    }

    /** 공개 사전등록 접수(인증 불필요) — 중복 이메일은 기존 등록 재반환. */
    @Audited(action = "VISITOR_REGISTER", targetType = "visitor_registration")
    @PostMapping("/api/public/events/{eventId}/register")
    public ApiResponse<RegisterResult> register(@PathVariable String eventId,
                                                @RequestBody RegisterRequest req) {
        return ApiResponse.ok(service.register(eventId, req));
    }

    /** 등록 대시보드 요약(집계·추이·유형 분포·폼). */
    @GetMapping("/api/events/{eventId}/visitors/summary")
    public ApiResponse<VisitorSummary> summary(@AuthenticationPrincipal KintexPrincipal principal,
                                               @PathVariable String eventId) {
        guard.requireEventAccess(principal, eventId);
        return ApiResponse.ok(service.summary(eventId));
    }

    /** 등록자 목록(마스킹). */
    @GetMapping("/api/events/{eventId}/visitors")
    public ApiResponse<PageResponse<VisitorListItem>> visitors(@AuthenticationPrincipal KintexPrincipal principal,
                                                               @PathVariable String eventId,
                                                               @RequestParam(defaultValue = "0") int page,
                                                               @RequestParam(defaultValue = "20") int size) {
        guard.requireEventAccess(principal, eventId);
        return ApiResponse.ok(service.visitors(eventId, page, size));
    }

    /** 리드 목록(마스킹 + AI 저장 스코어). booth 선택 필터. */
    @GetMapping("/api/events/{eventId}/leads")
    public ApiResponse<PageResponse<LeadItem>> leads(@AuthenticationPrincipal KintexPrincipal principal,
                                                     @PathVariable String eventId,
                                                     @RequestParam(required = false) String boothId,
                                                     @RequestParam(defaultValue = "0") int page,
                                                     @RequestParam(defaultValue = "50") int size) {
        guard.requireEventAccess(principal, eventId);
        return ApiResponse.ok(service.leads(eventId, boothId, page, size));
    }

    // ── SCR-31 현장 체크인 ──

    /** QR 토큰/등록번호 체크인(중복 방지). 홀매니저·주최자 현장 운영 역할. */
    @Audited(action = "VISITOR_CHECKIN", targetType = "visitor_registration")
    @PostMapping("/api/events/{eventId}/checkin")
    public ApiResponse<CheckinResult> checkin(@AuthenticationPrincipal KintexPrincipal principal,
                                              @PathVariable String eventId,
                                              @RequestBody CheckinRequest req) {
        guard.requireRole(principal, eventId, EventRole.HALL_MANAGER, EventRole.ORGANIZER);
        return ApiResponse.ok(service.checkin(eventId, req));
    }

    /** 현장 수동 검색(마스킹 결과). */
    @GetMapping("/api/events/{eventId}/checkin/search")
    public ApiResponse<List<CheckinSearchItem>> checkinSearch(@AuthenticationPrincipal KintexPrincipal principal,
                                                              @PathVariable String eventId,
                                                              @RequestParam("q") String q) {
        guard.requireRole(principal, eventId, EventRole.HALL_MANAGER, EventRole.ORGANIZER);
        return ApiResponse.ok(service.searchForCheckin(eventId, q));
    }

    /** 실시간 입장 집계(시간대별·장내 추정). */
    @GetMapping("/api/events/{eventId}/checkin/stats")
    public ApiResponse<CheckinStats> checkinStats(@AuthenticationPrincipal KintexPrincipal principal,
                                                  @PathVariable String eventId) {
        guard.requireEventAccess(principal, eventId);
        return ApiResponse.ok(service.checkinStats(eventId));
    }

    /** 배지 재발급. */
    @Audited(action = "VISITOR_BADGE_REISSUE", targetType = "visitor_registration")
    @PostMapping("/api/events/{eventId}/visitors/{registrationId}/badge/reissue")
    public ApiResponse<BadgeReissueResult> reissueBadge(@AuthenticationPrincipal KintexPrincipal principal,
                                                        @PathVariable String eventId,
                                                        @PathVariable String registrationId) {
        guard.requireRole(principal, eventId, EventRole.HALL_MANAGER, EventRole.ORGANIZER);
        return ApiResponse.ok(service.reissueBadge(eventId, registrationId));
    }

    // ── SCR-32 리드 수집·내보내기 ──

    /** 리드 수집(참가업체 부스 스캔) — 서버 규칙 엔진이 스코어 산출. */
    @Audited(action = "LEAD_COLLECT", targetType = "lead")
    @PostMapping("/api/events/{eventId}/leads")
    public ApiResponse<LeadCollectResult> collectLead(@AuthenticationPrincipal KintexPrincipal principal,
                                                      @PathVariable String eventId,
                                                      @RequestBody LeadCollectRequest req) {
        guard.requireRole(principal, eventId, EventRole.EXHIBITOR, EventRole.ORGANIZER, EventRole.HALL_MANAGER);
        return ApiResponse.ok(service.collectLead(eventId, req));
    }

    /**
     * 리드 AI 재계산(F051) — 매니저 이상(주최자·홀매니저). AiTextRouter 로 비-PII 신호를 요약해 스코어·근거를
     * 재산출하고, AI 실패 시 기존 규칙 스코어를 유지한다(ai_generated 정직 표기).
     */
    @Audited(action = "LEAD_RESCORE", targetType = "lead")
    @PostMapping("/api/events/{eventId}/leads/{leadId}/rescore")
    public ApiResponse<LeadRescoreResult> rescoreLead(@AuthenticationPrincipal KintexPrincipal principal,
                                                      @PathVariable String eventId,
                                                      @PathVariable String leadId) {
        guard.requireRole(principal, eventId, EventRole.ORGANIZER, EventRole.HALL_MANAGER);
        return ApiResponse.ok(service.rescoreLead(eventId, leadId));
    }

    /** 리드 CSV 내보내기(마스킹 필드만). UTF-8 BOM 포함(엑셀 한글 호환). */
    @Audited(action = "LEAD_EXPORT_CSV", targetType = "lead")
    @GetMapping("/api/events/{eventId}/leads/export")
    public ResponseEntity<byte[]> exportLeadsCsv(@AuthenticationPrincipal KintexPrincipal principal,
                                                 @PathVariable String eventId,
                                                 @RequestParam(required = false) String boothId) {
        guard.requireRole(principal, eventId, EventRole.EXHIBITOR, EventRole.ORGANIZER, EventRole.HALL_MANAGER);
        String csv = service.leadsCsv(eventId, boothId);
        byte[] bom = new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF};
        byte[] body = csv.getBytes(StandardCharsets.UTF_8);
        byte[] out = new byte[bom.length + body.length];
        System.arraycopy(bom, 0, out, 0, bom.length);
        System.arraycopy(body, 0, out, bom.length, body.length);
        return ResponseEntity.ok()
                .contentType(new MediaType("text", "csv", StandardCharsets.UTF_8))
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"leads-" + eventId + ".csv\"")
                .body(out);
    }
}
