package services

import (
	"encoding/json"
	"fmt"
	"stocksearch/models"
	"time"
)

// Kospi200Service 코스피200 종목 조회 서비스
type Kospi200Service struct {
	kiwoom *KiwoomClient
	cache  *CacheService
}

var kospi200Svc *Kospi200Service

// GetKospi200Service 코스피200 서비스 싱글턴 반환
func GetKospi200Service() *Kospi200Service {
	if kospi200Svc == nil {
		kospi200Svc = &Kospi200Service{
			kiwoom: GetKiwoomClient(),
			cache:  GetCacheService(),
		}
	}
	return kospi200Svc
}

// GetStocks ka20002: 코스피200 구성종목 전체 조회 (연속조회, 캐시 1분)
func (s *Kospi200Service) GetStocks() ([]models.Kospi200Stock, error) {
	const cacheKey = "kospi200_stocks"
	if cached, ok := s.cache.Get(cacheKey); ok {
		if stocks, ok := cached.([]models.Kospi200Stock); ok {
			return stocks, nil
		}
	}

	var all []models.Kospi200Stock
	contYn, nextKey := "N", ""

	for {
		body, nextContYn, nextNextKey, err := s.kiwoom.postPaged(
			"ka20002", "/api/dostk/sect",
			map[string]string{
				"mrkt_tp": "0",   // 코스피
				"inds_cd": "201", // KOSPI200
				"stex_tp": "1",   // KRX
			},
			contYn, nextKey,
		)
		if err != nil {
			return nil, fmt.Errorf("코스피200 조회 실패: %w", err)
		}

		var result struct {
			IndsStkpc []struct {
				StkCd      string `json:"stk_cd"`
				StkNm      string `json:"stk_nm"`
				CurPrc     string `json:"cur_prc"`
				PredPreSig string `json:"pred_pre_sig"`
				PredPre    string `json:"pred_pre"`
				FluRt      string `json:"flu_rt"`
				NowTrdeQty string `json:"now_trde_qty"`
				OpenPric   string `json:"open_pric"`
				HighPric   string `json:"high_pric"`
				LowPric    string `json:"low_pric"`
			} `json:"inds_stkpc"`
			ReturnCode int    `json:"return_code"`
			ReturnMsg  string `json:"return_msg"`
		}
		if err := json.Unmarshal(body, &result); err != nil {
			return nil, fmt.Errorf("코스피200 응답 파싱 실패: %w", err)
		}
		if result.ReturnCode != 0 {
			return nil, fmt.Errorf("코스피200 조회 실패: %s", result.ReturnMsg)
		}

		for _, s := range result.IndsStkpc {
			// 종목코드·종목명이 없는 행은 건너뜀
			if s.StkCd == "" || s.StkNm == "" {
				continue
			}
			all = append(all, models.Kospi200Stock{
				Code:       s.StkCd,
				Name:       s.StkNm,
				CurPrc:     absParseIntSafe(s.CurPrc),
				PredPreSig: s.PredPreSig,
				PredPre:    parseIntSafe(s.PredPre),
				FluRt:      parseFloatSafe(s.FluRt),
				Volume:     absParseIntSafe(s.NowTrdeQty),
				Open:       absParseIntSafe(s.OpenPric),
				High:       absParseIntSafe(s.HighPric),
				Low:        absParseIntSafe(s.LowPric),
			})
		}

		// 연속조회 종료 조건
		if nextContYn != "Y" || nextNextKey == "" {
			break
		}
		contYn, nextKey = nextContYn, nextNextKey
	}

	s.cache.Set(cacheKey, all, time.Minute)
	return all, nil
}
