package com.goldenchart.controller;

import com.goldenchart.dto.BacktestRequest;
import com.goldenchart.dto.BacktestResponse;
import com.goldenchart.service.BacktestingService;
import com.goldenchart.service.IndicatorSettingsService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

/**
 * 백테스팅 실행 REST API.
 *
 * <p>POST /backtesting/run 에 BacktestRequest 를 전송하면
 * Ta4j 로 백테스팅을 수행하여 매수/매도 시그널과 통계를 반환합니다.
 */
@RestController
@RequestMapping("/backtesting")
@RequiredArgsConstructor
public class BacktestingController {

    private final BacktestingService     backtestingService;
    private final IndicatorSettingsService indicatorSettingsService;

    /**
     * 백테스팅 실행.
     *
     * <p>요청 예시:
     * <pre>
     * POST /backtesting/run
     * {
     *   "strategyId": 1,          // DB 전략 ID (선택)
     *   "buyCondition": {...},     // DSL 직접 전달 시 (strategyId 없을 때 사용)
     *   "sellCondition": {...},
     *   "bars": [{time, open, high, low, close, volume}, ...],
     *   "timeframe": "1D"
     * }
     * </pre>
     */
    @PostMapping("/run")
    public ResponseEntity<BacktestResponse> run(
            @RequestBody BacktestRequest req,
            @RequestHeader(value = "X-User-Id",   required = false) String userIdHeader,
            @RequestHeader(value = "X-Device-Id", required = false) String deviceId) {

        if (req.getBars() == null || req.getBars().isEmpty()) {
            return ResponseEntity.badRequest().build();
        }

        Long userId = parseUserId(userIdHeader);

        // DB 저장 파라미터를 기반으로, 요청 params 로 덮어쓰기
        // (요청에 params 없으면 DB 값만 사용 → 사용자가 변경한 파라미터 항상 반영)
        if (userId != null || deviceId != null) {
            java.util.Map<String, java.util.Map<String, Object>> dbParams =
                    indicatorSettingsService.getAll(userId, deviceId);
            if (!dbParams.isEmpty()) {
                java.util.Map<String, java.util.Map<String, Object>> merged =
                        new java.util.HashMap<>(dbParams);
                if (req.getIndicatorParams() != null) {
                    req.getIndicatorParams().forEach((type, params) ->
                        merged.merge(type, params, (dbP, reqP) -> {
                            java.util.Map<String, Object> m = new java.util.HashMap<>(dbP);
                            m.putAll(reqP);
                            return m;
                        })
                    );
                }
                req.setIndicatorParams(merged);
            }
        }

        BacktestResponse response = backtestingService.run(req);
        return ResponseEntity.ok(response);
    }

    private Long parseUserId(String header) {
        if (header == null || header.isBlank()) return null;
        try { return Long.parseLong(header); } catch (NumberFormatException e) { return null; }
    }
}
