package com.goldenchart.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.goldenchart.dto.StrategyDto;
import com.goldenchart.entity.GcStrategy;
import com.goldenchart.repository.GcStrategyRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

@Service
@RequiredArgsConstructor
@Slf4j
public class StrategyService {

    private final GcStrategyRepository repository;
    private final ObjectMapper objectMapper;
    private final StrategyConditionTimeframeService conditionTimeframes;

    // ── 조회 ──────────────────────────────────────────────────────────────────

    public List<StrategyDto> list(Long userId, String deviceId) {
        List<GcStrategy> entities = userId != null
                ? repository.findByUserIdOrderByUpdatedAtDesc(userId)
                : repository.findByDeviceIdOrderByUpdatedAtDesc(deviceId != null ? deviceId : "");
        return entities.stream().map(this::toDto).toList();
    }

    public Optional<StrategyDto> findById(Long id) {
        return repository.findById(id).map(this::toDto);
    }

    // ── 저장 / 수정 ───────────────────────────────────────────────────────────

    @Transactional
    public StrategyDto save(StrategyDto dto, Long userId, String deviceId) {
        GcStrategy entity;
        if (dto.getId() != null) {
            entity = repository.findById(dto.getId()).orElseGet(GcStrategy::new);
        } else {
            entity = new GcStrategy();
            entity.setUserId(userId);
            entity.setDeviceId(deviceId);
        }

        entity.setName(dto.getName() != null ? dto.getName() : "전략");
        entity.setDescription(dto.getDescription());
        if (dto.getEnabled() != null) entity.setEnabled(dto.getEnabled());
        else if (entity.getEnabled() == null) entity.setEnabled(true);

        try {
            entity.setBuyConditionJson(
                    dto.getBuyCondition() != null ? objectMapper.writeValueAsString(dto.getBuyCondition()) : null);
            entity.setSellConditionJson(
                    dto.getSellCondition() != null ? objectMapper.writeValueAsString(dto.getSellCondition()) : null);
        } catch (Exception e) {
            log.warn("전략 DSL 직렬화 실패: {}", e.getMessage());
        }

        GcStrategy saved = repository.save(entity);
        conditionTimeframes.invalidate(saved.getId());
        return toDto(saved);
    }

    // ── 삭제 ──────────────────────────────────────────────────────────────────

    @Transactional
    public void delete(Long id) {
        conditionTimeframes.invalidate(id);
        repository.deleteById(id);
    }

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

    private StrategyDto toDto(GcStrategy e) {
        StrategyDto dto = new StrategyDto();
        dto.setId(e.getId());
        dto.setName(e.getName());
        dto.setDescription(e.getDescription());
        dto.setEnabled(e.getEnabled());
        dto.setCreatedAt(e.getCreatedAt());
        dto.setUpdatedAt(e.getUpdatedAt());
        try {
            if (e.getBuyConditionJson() != null)
                dto.setBuyCondition(objectMapper.readTree(e.getBuyConditionJson()));
            if (e.getSellConditionJson() != null)
                dto.setSellCondition(objectMapper.readTree(e.getSellConditionJson()));
        } catch (Exception ex) {
            log.warn("전략 DSL 역직렬화 실패: {}", ex.getMessage());
        }
        return dto;
    }
}
