package com.goldenchart.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.goldenchart.entity.GcChartSlot;
import com.goldenchart.entity.GcChartWorkspace;
import com.goldenchart.service.ChartSettingsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 차트 워크스페이스 설정 REST API.
 *
 * GET  /api/chart/workspace          - 전체 설정 로드 (프론트 시작 시 호출)
 * POST /api/chart/workspace          - 전체 설정 저장
 * PUT  /api/chart/workspace/layout   - 레이아웃만 변경
 * PUT  /api/chart/slot/{index}       - 특정 슬롯 저장
 */
@RestController
@RequestMapping("/chart")
@RequiredArgsConstructor
@Slf4j
public class ChartSettingsController {

    private final ChartSettingsService settingsService;
    private final ObjectMapper objectMapper;

    /** 헤더에서 userId 또는 deviceId 추출 */
    private Long userId(Map<String, String> headers) {
        String v = headers.get("x-user-id");
        return v != null ? Long.parseLong(v) : null;
    }
    private String deviceId(Map<String, String> headers) {
        return headers.getOrDefault("x-device-id", "anonymous");
    }

    /**
     * 프론트엔드 시작 시 전체 워크스페이스 로드.
     * DB에 저장된 설정이 없으면 204 반환 → 프론트는 기본값 사용.
     */
    @GetMapping("/workspace")
    public ResponseEntity<?> getWorkspace(
            @RequestHeader Map<String, String> headers) {
        GcChartWorkspace ws = settingsService.getWorkspaceWithSlots(
            userId(headers), deviceId(headers));

        if (ws == null) return ResponseEntity.noContent().build();

        return ResponseEntity.ok(toDto(ws));
    }

    /**
     * 전체 워크스페이스 저장 (자동 저장 / 명시 저장).
     */
    @PostMapping("/workspace")
    public ResponseEntity<?> saveWorkspace(
            @RequestHeader Map<String, String> headers,
            @RequestBody Map<String, Object> body) {
        Long uid = userId(headers);
        String did = deviceId(headers);
        String layoutId = (String) body.getOrDefault("layoutId", "1");
        String syncJson = body.containsKey("syncOptions")
            ? toJson(body.get("syncOptions")) : null;
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> slotsData = (List<Map<String, Object>>) body.get("slots");

        GcChartWorkspace ws = settingsService.saveAll(uid, did, layoutId, syncJson,
            slotsData != null ? slotsData : List.of());
        return ResponseEntity.ok(toDto(ws));
    }

    /**
     * 레이아웃만 변경.
     */
    @PutMapping("/workspace/layout")
    public ResponseEntity<?> updateLayout(
            @RequestHeader Map<String, String> headers,
            @RequestBody Map<String, Object> body) {
        String layoutId = (String) body.get("layoutId");
        String syncJson = body.containsKey("syncOptions") ? toJson(body.get("syncOptions")) : null;
        GcChartWorkspace ws = settingsService.saveWorkspace(
            userId(headers), deviceId(headers), layoutId, syncJson);
        return ResponseEntity.ok(Map.of("layoutId", ws.getLayoutId()));
    }

    /**
     * 특정 슬롯 설정 저장.
     */
    @PutMapping("/slot/{slotIndex}")
    public ResponseEntity<?> saveSlot(
            @RequestHeader Map<String, String> headers,
            @PathVariable int slotIndex,
            @RequestBody Map<String, Object> body) {
        GcChartSlot slot = settingsService.saveSlot(
            userId(headers), deviceId(headers), slotIndex, body);
        return ResponseEntity.ok(slotToDto(slot));
    }

    // ── DTO 변환 ────────────────────────────────────────────────────────────────

    private Map<String, Object> toDto(GcChartWorkspace ws) {
        Map<String, Object> dto = new HashMap<>();
        dto.put("id", ws.getId());
        dto.put("layoutId", ws.getLayoutId());
        dto.put("syncOptions", parseJson(ws.getSyncOptionsJson()));
        dto.put("slots", ws.getSlots().stream()
            .map(this::slotToDto)
            .collect(Collectors.toList()));
        return dto;
    }

    private Map<String, Object> slotToDto(GcChartSlot s) {
        Map<String, Object> dto = new HashMap<>();
        dto.put("slotIndex",       s.getSlotIndex());
        dto.put("symbol",          s.getSymbol());
        dto.put("timeframe",       s.getTimeframe());
        dto.put("chartType",       s.getChartType());
        dto.put("theme",           s.getTheme());
        dto.put("mode",            s.getMode());
        dto.put("logScale",        s.getLogScale());
        dto.put("drawingsLocked",  s.getDrawingsLocked());
        dto.put("drawingsVisible", s.getDrawingsVisible());
        dto.put("indicators",      parseJson(s.getIndicatorsJson()));
        dto.put("drawings",        parseJson(s.getDrawingsJson()));
        dto.put("paneLayout",      parseJson(s.getPaneLayoutJson()));
        dto.put("mainChartStyle",  parseJson(s.getMainChartStyleJson()));
        return dto;
    }

    private Object parseJson(String json) {
        if (json == null) return null;
        try { return objectMapper.readValue(json, Object.class); }
        catch (Exception e) { return null; }
    }

    private String toJson(Object obj) {
        try { return objectMapper.writeValueAsString(obj); }
        catch (Exception e) { return null; }
    }
}
