package com.zioinfo.kintex.system.message;

import com.zioinfo.kintex.auth.EventAccessGuard;
import com.zioinfo.kintex.auth.KintexPrincipal;
import com.zioinfo.kintex.common.ApiResponse;
import com.zioinfo.kintex.common.audit.Audited;
import com.zioinfo.kintex.system.SystemAccessGuard;
import jakarta.validation.Valid;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

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

/**
 * 메시지 관리 API. 관리(CRUD)는 ADMIN(시스템관리 게이트), 렌더는 인증 사용자 공개.
 *  - GET  /api/admin/messages            목록(category/locale 필터)  [ADMIN]
 *  - GET  /api/admin/messages/{code}     코드별 로케일 목록           [ADMIN]
 *  - POST /api/admin/messages            생성/수정(upsert)            [ADMIN]
 *  - PUT  /api/admin/messages/{code}     수정(upsert)                 [ADMIN]
 *  - DELETE /api/admin/messages/{code}   삭제(locale 옵션)            [ADMIN]
 *  - POST /api/messages/{code}/render    {params:{...}} → 치환 문자열  [인증]
 */
@RestController("sysMessageController")
public class MessageController {

    private final MessageService service;
    private final EventAccessGuard authGuard;
    private final SystemAccessGuard adminGuard;

    public MessageController(MessageService service, EventAccessGuard authGuard, SystemAccessGuard adminGuard) {
        this.service = service;
        this.authGuard = authGuard;
        this.adminGuard = adminGuard;
    }

    @GetMapping("/api/admin/messages")
    public ApiResponse<List<MessageDto>> list(@AuthenticationPrincipal KintexPrincipal principal,
                                              @RequestParam(required = false) String category,
                                              @RequestParam(required = false) String locale) {
        adminGuard.requireAdmin(principal);
        return ApiResponse.ok(service.list(principal.tenantId(), category, locale));
    }

    @GetMapping("/api/admin/messages/{code}")
    public ApiResponse<List<MessageDto>> byCode(@AuthenticationPrincipal KintexPrincipal principal,
                                                @PathVariable String code) {
        adminGuard.requireAdmin(principal);
        return ApiResponse.ok(service.byCode(principal.tenantId(), code));
    }

    @Audited(action = "SYS_MESSAGE_SAVE", targetType = "sys_message")
    @PostMapping("/api/admin/messages")
    public ApiResponse<Void> create(@AuthenticationPrincipal KintexPrincipal principal,
                                    @Valid @RequestBody MessageDto dto) {
        adminGuard.requireAdmin(principal);
        service.save(principal.tenantId(), dto);
        return ApiResponse.ok(null);
    }

    @Audited(action = "SYS_MESSAGE_SAVE", targetType = "sys_message")
    @PutMapping("/api/admin/messages/{code}")
    public ApiResponse<Void> update(@AuthenticationPrincipal KintexPrincipal principal,
                                    @PathVariable String code, @Valid @RequestBody MessageDto dto) {
        adminGuard.requireAdmin(principal);
        MessageDto merged = new MessageDto(code, dto.locale(), dto.category(), dto.title(),
                dto.template(), dto.useYn(), null);
        service.save(principal.tenantId(), merged);
        return ApiResponse.ok(null);
    }

    @Audited(action = "SYS_MESSAGE_DELETE", targetType = "sys_message")
    @DeleteMapping("/api/admin/messages/{code}")
    public ApiResponse<Void> delete(@AuthenticationPrincipal KintexPrincipal principal,
                                    @PathVariable String code,
                                    @RequestParam(required = false) String locale) {
        adminGuard.requireAdmin(principal);
        service.delete(principal.tenantId(), code, locale);
        return ApiResponse.ok(null);
    }

    /** 렌더 — {params:{name:..,eventName:..}} 를 받아 template 치환 결과 반환. */
    @PostMapping("/api/messages/{code}/render")
    public ApiResponse<RenderResult> render(@AuthenticationPrincipal KintexPrincipal principal,
                                            @PathVariable String code,
                                            @RequestParam(required = false) String locale,
                                            @RequestBody(required = false) RenderRequest body) {
        authGuard.require(principal);
        Map<String, Object> params = body == null || body.params() == null ? Map.of() : body.params();
        String loc = (locale != null && !locale.isBlank()) ? locale
                : (body != null ? body.locale() : null);
        String text = service.render(principal.tenantId(), code, loc, params);
        return ApiResponse.ok(new RenderResult(code, loc, text));
    }

    /** 렌더 요청 본문 — params 는 {key}→값 매핑. locale 은 쿼리 우선, 없으면 본문. */
    public record RenderRequest(String locale, Map<String, Object> params) {
    }

    /** 렌더 결과. */
    public record RenderResult(String code, String locale, String text) {
    }
}
