package handlers

import (
	"encoding/json"
	"net/http"
	"stocksearch/models"
	"stocksearch/services"
	"strings"
)

// StockHandler JSON REST API 핸들러
type StockHandler struct {
	stockService    *services.StockService
	scannerService  *services.ScannerService
	indexService    *services.IndexService
	searchService   *services.SearchService
	dartService     *services.DartService
	newsService     *services.NewsService
	themeService    *services.ThemeService
	kospi200Service *services.Kospi200Service
	watchlistSvc    *services.WatchlistService
}

// NewStockHandler 핸들러 초기화
func NewStockHandler(watchlistSvc *services.WatchlistService) *StockHandler {
	return &StockHandler{
		stockService:    services.GetStockService(),
		scannerService:  services.GetScannerService(),
		indexService:    services.GetIndexService(),
		searchService:   services.GetSearchService(),
		dartService:     services.GetDartService(),
		newsService:     services.GetNewsService(),
		themeService:    services.GetThemeService(),
		kospi200Service: services.GetKospi200Service(),
		watchlistSvc:    watchlistSvc,
	}
}

// GetCurrentPrice GET /api/stock/{code} - 주식 현재가 JSON 반환
func (h *StockHandler) GetCurrentPrice(w http.ResponseWriter, r *http.Request) {
	code := strings.TrimPrefix(r.PathValue("code"), "")
	if code == "" {
		jsonError(w, "종목코드가 필요합니다.", http.StatusBadRequest)
		return
	}

	price, err := h.stockService.GetCurrentPrice(code)
	if err != nil {
		jsonError(w, err.Error(), http.StatusInternalServerError)
		return
	}

	jsonOK(w, price)
}

// GetChart GET /api/stock/{code}/chart?period=daily|minute1|minute5 - 차트 데이터 JSON 반환
func (h *StockHandler) GetDailyChart(w http.ResponseWriter, r *http.Request) {
	code := r.PathValue("code")
	if code == "" {
		jsonError(w, "종목코드가 필요합니다.", http.StatusBadRequest)
		return
	}

	period := r.URL.Query().Get("period")
	var (
		candles []models.CandleData
		err     error
	)

	switch period {
	case "minute1":
		candles, err = h.stockService.GetMinuteChart(code, 1)
	case "minute5":
		candles, err = h.stockService.GetMinuteChart(code, 5)
	default:
		candles, err = h.stockService.GetDailyChart(code)
	}

	if err != nil {
		jsonError(w, err.Error(), http.StatusInternalServerError)
		return
	}

	jsonOK(w, candles)
}

// GetScannerStatus GET /api/scanner/status - 스캐너 활성화 상태 반환
func (h *StockHandler) GetScannerStatus(w http.ResponseWriter, r *http.Request) {
	jsonOK(w, map[string]bool{"enabled": h.scannerService.IsEnabled()})
}

// ToggleScanner POST /api/scanner/toggle - 스캐너 ON/OFF 토글 후 새 상태 반환
func (h *StockHandler) ToggleScanner(w http.ResponseWriter, r *http.Request) {
	next := !h.scannerService.IsEnabled()
	h.scannerService.SetEnabled(next)
	jsonOK(w, map[string]bool{"enabled": next})
}

// GetSignals GET /api/signal - 체결강도 상승 감지 시그널 종목 JSON 반환
func (h *StockHandler) GetSignals(w http.ResponseWriter, r *http.Request) {
	signals := h.scannerService.GetSignals()
	jsonOK(w, signals)
}

// GetWatchlistSignals GET /api/watchlist-signal?codes=005930,000660,... - 관심종목 복합 분석 JSON 반환
func (h *StockHandler) GetWatchlistSignals(w http.ResponseWriter, r *http.Request) {
	raw := r.URL.Query().Get("codes")
	if raw == "" {
		jsonOK(w, []services.SignalStock{})
		return
	}
	parts := strings.Split(raw, ",")
	// 최대 20개 제한
	codes := make([]string, 0, 20)
	for _, c := range parts {
		c = strings.TrimSpace(c)
		if len(c) == 6 {
			codes = append(codes, c)
		}
		if len(codes) >= 20 {
			break
		}
	}
	if len(codes) == 0 {
		jsonOK(w, []services.SignalStock{})
		return
	}
	signals := h.scannerService.AnalyzeWatchlist(codes)
	if signals == nil {
		signals = []services.SignalStock{}
	}
	jsonOK(w, signals)
}

// Search GET /api/search?q=... - 종목명·코드 검색 결과 JSON 반환
func (h *StockHandler) Search(w http.ResponseWriter, r *http.Request) {
	q := r.URL.Query().Get("q")
	results := h.searchService.Search(q)
	if results == nil {
		results = []services.StockItem{}
	}
	jsonOK(w, results)
}

// GetIndices GET /api/indices - 코스피·코스닥·다우·나스닥 지수 JSON 반환
func (h *StockHandler) GetIndices(w http.ResponseWriter, r *http.Request) {
	quotes, err := h.indexService.GetIndices()
	if err != nil {
		jsonError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	jsonOK(w, quotes)
}

// GetNews GET /api/news?name={stockName} - 종목 관련 최근 뉴스 JSON 반환
func (h *StockHandler) GetNews(w http.ResponseWriter, r *http.Request) {
	name := r.URL.Query().Get("name")
	if name == "" {
		jsonError(w, "종목명이 필요합니다.", http.StatusBadRequest)
		return
	}
	news, err := h.newsService.GetNews(name)
	if err != nil {
		jsonError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	jsonOK(w, news)
}

// GetDisclosures GET /api/disclosure?code={stockCode} - DART 최근 공시 JSON 반환
func (h *StockHandler) GetDisclosures(w http.ResponseWriter, r *http.Request) {
	code := r.URL.Query().Get("code")
	if len(code) != 6 {
		jsonError(w, "올바른 종목코드를 입력해주세요.", http.StatusBadRequest)
		return
	}
	disclosures, err := h.dartService.GetDisclosures(code)
	if err != nil {
		jsonError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	jsonOK(w, disclosures)
}

// GetKospi200 GET /api/kospi200 - 코스피200 구성종목 JSON 반환
func (h *StockHandler) GetKospi200(w http.ResponseWriter, r *http.Request) {
	stocks, err := h.kospi200Service.GetStocks()
	if err != nil {
		jsonError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	jsonOK(w, stocks)
}

// GetThemes GET /api/themes?date=1&sort=3 - 테마그룹 목록 JSON 반환
// sort: 3=상위등락률(기본), 1=상위기간수익률
func (h *StockHandler) GetThemes(w http.ResponseWriter, r *http.Request) {
	dateTp := r.URL.Query().Get("date")
	if dateTp == "" {
		dateTp = "1"
	}
	sortTp := r.URL.Query().Get("sort")
	if sortTp == "" {
		sortTp = "3"
	}
	groups, err := h.themeService.GetThemes(dateTp, sortTp)
	if err != nil {
		jsonError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	jsonOK(w, groups)
}

// GetThemeStocks GET /api/themes/{code}?date=1 - 테마구성종목 JSON 반환
func (h *StockHandler) GetThemeStocks(w http.ResponseWriter, r *http.Request) {
	code := r.PathValue("code")
	if code == "" {
		jsonError(w, "테마코드가 필요합니다.", http.StatusBadRequest)
		return
	}
	dateTp := r.URL.Query().Get("date")
	if dateTp == "" {
		dateTp = "1"
	}
	detail, err := h.themeService.GetThemeStocks(code, dateTp)
	if err != nil {
		jsonError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	jsonOK(w, detail)
}

// GetWatchlist GET /api/watchlist — 관심종목 목록 JSON 반환
func (h *StockHandler) GetWatchlist(w http.ResponseWriter, r *http.Request) {
	list := h.watchlistSvc.GetAll()
	if list == nil {
		list = []services.WatchlistItem{}
	}
	jsonOK(w, list)
}

// AddWatchlist POST /api/watchlist — body: {code, name} 관심종목 추가
func (h *StockHandler) AddWatchlist(w http.ResponseWriter, r *http.Request) {
	var body struct {
		Code string `json:"code"`
		Name string `json:"name"`
	}
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		jsonError(w, "잘못된 요청입니다.", http.StatusBadRequest)
		return
	}
	if len(body.Code) != 6 {
		jsonError(w, "올바른 종목코드를 입력해주세요.", http.StatusBadRequest)
		return
	}
	if err := h.watchlistSvc.Add(body.Code, body.Name); err != nil {
		jsonError(w, err.Error(), http.StatusConflict)
		return
	}
	jsonOK(w, map[string]bool{"ok": true})
}

// RemoveWatchlist DELETE /api/watchlist/{code} — 관심종목 삭제
func (h *StockHandler) RemoveWatchlist(w http.ResponseWriter, r *http.Request) {
	code := r.PathValue("code")
	if len(code) != 6 {
		jsonError(w, "올바른 종목코드를 입력해주세요.", http.StatusBadRequest)
		return
	}
	if err := h.watchlistSvc.Remove(code); err != nil {
		jsonError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	jsonOK(w, map[string]bool{"ok": true})
}

// --- JSON 응답 헬퍼 ---

func jsonOK(w http.ResponseWriter, data interface{}) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	json.NewEncoder(w).Encode(data)
}

func jsonError(w http.ResponseWriter, message string, status int) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(status)
	json.NewEncoder(w).Encode(map[string]string{"error": message})
}
