package com.zioinfo.cms.member;

import com.zioinfo.cms.common.ApiResponse;
import com.zioinfo.cms.common.CryptoUtil;
import com.zioinfo.cms.integration.CrmClient;
import com.zioinfo.cms.member.mapper.MemberMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

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

/**
 * 회원 관리 API.
 *
 * <p>보안 불변 규칙: email/phone PII는 CryptoUtil 암호화 저장, 모든 응답은 마스킹.
 * CRM 연계로 고객 인사이트 조회.
 */
@RestController
@RequestMapping("/api/cms/member")
@RequiredArgsConstructor
public class MemberController {

    private final MemberMapper mapper;
    private final CryptoUtil crypto;
    private final CrmClient crmClient;

    @GetMapping
    public ApiResponse<List<CmsMember>> list(@RequestParam(required = false) String segment,
                                             @RequestParam(required = false) String status,
                                             @RequestParam(required = false) String keyword) {
        List<CmsMember> all = mapper.findAll(segment, status, keyword);
        all.forEach(this::mask);
        return ApiResponse.ok(all);
    }

    @GetMapping("/{id}")
    public ApiResponse<CmsMember> get(@PathVariable Long id) {
        return ApiResponse.ok(mask(require(id)));
    }

    @PostMapping
    public ApiResponse<CmsMember> create(@RequestBody Map<String, Object> req) {
        CmsMember m = new CmsMember();
        m.setMemberCode(str(req.get("memberCode")));
        m.setName(str(req.get("name")));
        m.setEmailEnc(encOrNull(str(req.get("email"))));
        m.setPhoneEnc(encOrNull(str(req.get("phone"))));
        m.setSegment(req.get("segment") == null ? "NEW" : str(req.get("segment")));
        m.setStatus(req.get("status") == null ? "ACTIVE" : str(req.get("status")));
        m.setCrmCustomerId(str(req.get("crmCustomerId")));
        mapper.insert(m);
        return ApiResponse.ok(mask(mapper.findById(m.getId())));
    }

    @PutMapping("/{id}")
    public ApiResponse<CmsMember> update(@PathVariable Long id, @RequestBody Map<String, Object> req) {
        CmsMember m = require(id);
        if (req.containsKey("name")) m.setName(str(req.get("name")));
        if (req.containsKey("email")) m.setEmailEnc(encOrNull(str(req.get("email"))));
        if (req.containsKey("phone")) m.setPhoneEnc(encOrNull(str(req.get("phone"))));
        if (req.containsKey("segment")) m.setSegment(str(req.get("segment")));
        if (req.containsKey("status")) m.setStatus(str(req.get("status")));
        if (req.containsKey("crmCustomerId")) m.setCrmCustomerId(str(req.get("crmCustomerId")));
        mapper.update(m);
        return ApiResponse.ok(mask(mapper.findById(id)));
    }

    /** CRM 고객 인사이트 (이메일 평문은 서버 내부에서만 사용, 응답 노출 없음). */
    @GetMapping("/{id}/crm-insight")
    public ApiResponse<Map<String, Object>> crmInsight(@PathVariable Long id) {
        CmsMember m = require(id);
        String email = m.getEmailEnc() == null ? null : crypto.decrypt(m.getEmailEnc());
        if (email == null || email.isBlank()) {
            return ApiResponse.ok(Map.of("note", "이메일 미등록 — 인사이트 조회 불가"));
        }
        return ApiResponse.ok(crmClient.getCustomerInsight(email));
    }

    @DeleteMapping("/{id}")
    public ApiResponse<Void> delete(@PathVariable Long id) {
        mapper.delete(id);
        return ApiResponse.ok(null);
    }

    // ── helpers ──
    private CmsMember require(Long id) {
        CmsMember m = mapper.findById(id);
        if (m == null) throw new RuntimeException("ERR-CMS-MEMBER-404: 회원 없음");
        return m;
    }

    /** 응답용 마스킹 — emailEnc/phoneEnc 를 복호화→마스킹 후 같은 필드에 담아 노출. */
    private CmsMember mask(CmsMember m) {
        if (m.getEmailEnc() != null) m.setEmailEnc(CryptoUtil.mask(crypto.decrypt(m.getEmailEnc())));
        if (m.getPhoneEnc() != null) m.setPhoneEnc(CryptoUtil.mask(crypto.decrypt(m.getPhoneEnc())));
        return m;
    }

    private String encOrNull(String plain) {
        return (plain == null || plain.isBlank()) ? null : crypto.encrypt(plain);
    }

    private String str(Object o) { return o == null ? null : String.valueOf(o); }
}
