package services

import (
	"database/sql"
	"encoding/json"
	"log"
	"stocksearch/models"
	"time"
)

// --- Rules ---

func dbInsertRule(rule models.AutoTradeRule) {
	if db == nil {
		return
	}
	_, err := db.Exec(`INSERT INTO autotrade_rules
		(id, name, enabled, min_rise_score, min_cntr_str, require_bullish,
		 order_amount, max_positions, stop_loss1_pct, stop_loss1_count,
		 stop_loss_pct, take_profit_pct, max_hold_minutes, exit_before_close, created_at)
		VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15)`,
		rule.ID, rule.Name, rule.Enabled,
		rule.MinRiseScore, rule.MinCntrStr, rule.RequireBullish,
		rule.OrderAmount, rule.MaxPositions,
		rule.StopLoss1Pct, rule.StopLoss1Count, rule.StopLossPct,
		rule.TakeProfitPct, rule.MaxHoldMinutes, rule.ExitBeforeClose, rule.CreatedAt)
	if err != nil {
		log.Printf("DB 규칙 삽입 실패: %v", err)
	}
}

func dbUpdateRule(rule models.AutoTradeRule) {
	if db == nil {
		return
	}
	_, err := db.Exec(`UPDATE autotrade_rules SET
		name=$2, enabled=$3, min_rise_score=$4, min_cntr_str=$5, require_bullish=$6,
		order_amount=$7, max_positions=$8, stop_loss1_pct=$9, stop_loss1_count=$10,
		stop_loss_pct=$11, take_profit_pct=$12, max_hold_minutes=$13, exit_before_close=$14
		WHERE id=$1`,
		rule.ID, rule.Name, rule.Enabled,
		rule.MinRiseScore, rule.MinCntrStr, rule.RequireBullish,
		rule.OrderAmount, rule.MaxPositions,
		rule.StopLoss1Pct, rule.StopLoss1Count, rule.StopLossPct,
		rule.TakeProfitPct, rule.MaxHoldMinutes, rule.ExitBeforeClose)
	if err != nil {
		log.Printf("DB 규칙 수정 실패: %v", err)
	}
}

func dbDeleteRule(id string) {
	if db == nil {
		return
	}
	if _, err := db.Exec(`DELETE FROM autotrade_rules WHERE id=$1`, id); err != nil {
		log.Printf("DB 규칙 삭제 실패: %v", err)
	}
}

func dbLoadRules() []models.AutoTradeRule {
	if db == nil {
		return nil
	}
	rows, err := db.Query(`SELECT id, name, enabled, min_rise_score, min_cntr_str, require_bullish,
		order_amount, max_positions, stop_loss1_pct, stop_loss1_count,
		stop_loss_pct, take_profit_pct, max_hold_minutes, exit_before_close, created_at
		FROM autotrade_rules ORDER BY created_at`)
	if err != nil {
		log.Printf("DB 규칙 조회 실패: %v", err)
		return nil
	}
	defer rows.Close()

	var rules []models.AutoTradeRule
	for rows.Next() {
		var r models.AutoTradeRule
		if err := rows.Scan(&r.ID, &r.Name, &r.Enabled,
			&r.MinRiseScore, &r.MinCntrStr, &r.RequireBullish,
			&r.OrderAmount, &r.MaxPositions,
			&r.StopLoss1Pct, &r.StopLoss1Count, &r.StopLossPct,
			&r.TakeProfitPct, &r.MaxHoldMinutes, &r.ExitBeforeClose, &r.CreatedAt); err != nil {
			log.Printf("DB 규칙 스캔 실패: %v", err)
			continue
		}
		rules = append(rules, r)
	}
	return rules
}

// --- Positions ---

func dbInsertPosition(pos *models.AutoTradePosition) {
	if db == nil {
		return
	}
	err := db.QueryRow(`INSERT INTO autotrade_positions
		(code, name, buy_price, qty, order_no, entry_time, rule_id,
		 stop_loss1, stop_loss1_touches, stop_loss, take_profit, status)
		VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12) RETURNING id`,
		pos.Code, pos.Name, pos.BuyPrice, pos.Qty, pos.OrderNo, pos.EntryTime, pos.RuleID,
		pos.StopLoss1, pos.StopLoss1Touches, pos.StopLoss, pos.TakeProfit, pos.Status).Scan(&pos.DBID)
	if err != nil {
		log.Printf("DB 포지션 삽입 실패: %v", err)
	}
}

func dbUpdatePosition(pos *models.AutoTradePosition) {
	if db == nil {
		return
	}
	var exitTime *time.Time
	if !pos.ExitTime.IsZero() {
		exitTime = &pos.ExitTime
	}
	_, err := db.Exec(`UPDATE autotrade_positions SET
		buy_price=$2, qty=$3, order_no=$4, stop_loss1=$5, stop_loss1_touches=$6,
		stop_loss=$7, take_profit=$8, status=$9, exit_time=$10, exit_price=$11, exit_reason=$12
		WHERE id=$1`,
		pos.DBID, pos.BuyPrice, pos.Qty, pos.OrderNo,
		pos.StopLoss1, pos.StopLoss1Touches, pos.StopLoss, pos.TakeProfit,
		pos.Status, exitTime, pos.ExitPrice, pos.ExitReason)
	if err != nil {
		log.Printf("DB 포지션 수정 실패: %v", err)
	}
}

func dbLoadActivePositions() map[string]*models.AutoTradePosition {
	if db == nil {
		return nil
	}
	rows, err := db.Query(`SELECT id, code, name, buy_price, qty, order_no, entry_time, rule_id,
		stop_loss1, stop_loss1_touches, stop_loss, take_profit, status
		FROM autotrade_positions WHERE status IN ('pending', 'open')`)
	if err != nil {
		log.Printf("DB 활성 포지션 조회 실패: %v", err)
		return nil
	}
	defer rows.Close()

	positions := make(map[string]*models.AutoTradePosition)
	for rows.Next() {
		var p models.AutoTradePosition
		if err := rows.Scan(&p.DBID, &p.Code, &p.Name, &p.BuyPrice, &p.Qty, &p.OrderNo,
			&p.EntryTime, &p.RuleID, &p.StopLoss1, &p.StopLoss1Touches,
			&p.StopLoss, &p.TakeProfit, &p.Status); err != nil {
			log.Printf("DB 포지션 스캔 실패: %v", err)
			continue
		}
		positions[p.Code] = &p
	}
	return positions
}

func dbLoadClosedPositions(limit int) []*models.AutoTradePosition {
	if db == nil {
		return nil
	}
	rows, err := db.Query(`SELECT id, code, name, buy_price, qty, order_no, entry_time, rule_id,
		stop_loss1, stop_loss1_touches, stop_loss, take_profit, status,
		exit_time, exit_price, exit_reason
		FROM autotrade_positions WHERE status='closed'
		ORDER BY exit_time DESC LIMIT $1`, limit)
	if err != nil {
		log.Printf("DB 종료 포지션 조회 실패: %v", err)
		return nil
	}
	defer rows.Close()

	var positions []*models.AutoTradePosition
	for rows.Next() {
		var p models.AutoTradePosition
		var exitTime sql.NullTime
		if err := rows.Scan(&p.DBID, &p.Code, &p.Name, &p.BuyPrice, &p.Qty, &p.OrderNo,
			&p.EntryTime, &p.RuleID, &p.StopLoss1, &p.StopLoss1Touches,
			&p.StopLoss, &p.TakeProfit, &p.Status,
			&exitTime, &p.ExitPrice, &p.ExitReason); err != nil {
			log.Printf("DB 종료 포지션 스캔 실패: %v", err)
			continue
		}
		if exitTime.Valid {
			p.ExitTime = exitTime.Time
		}
		positions = append(positions, &p)
	}
	return positions
}

func dbGetTodayStats() (tradeCount int, totalPL int64) {
	if db == nil {
		return 0, 0
	}
	today := time.Now().Truncate(24 * time.Hour)
	row := db.QueryRow(`SELECT COALESCE(COUNT(*), 0), COALESCE(SUM((exit_price - buy_price) * qty), 0)
		FROM autotrade_positions WHERE status='closed' AND exit_time >= $1`, today)
	if err := row.Scan(&tradeCount, &totalPL); err != nil {
		log.Printf("DB 통계 조회 실패: %v", err)
	}
	return
}

// --- Logs ---

func dbInsertLog(l models.AutoTradeLog) {
	if db == nil {
		return
	}
	_, err := db.Exec(`INSERT INTO autotrade_logs (at, level, message, code) VALUES ($1,$2,$3,$4)`,
		l.At, l.Level, l.Message, l.Code)
	if err != nil {
		log.Printf("DB 로그 삽입 실패: %v", err)
	}
}

func dbLoadRecentLogs(limit int) []models.AutoTradeLog {
	if db == nil {
		return nil
	}
	rows, err := db.Query(`SELECT at, level, message, code FROM autotrade_logs
		ORDER BY at DESC LIMIT $1`, limit)
	if err != nil {
		log.Printf("DB 로그 조회 실패: %v", err)
		return nil
	}
	defer rows.Close()

	var logs []models.AutoTradeLog
	for rows.Next() {
		var l models.AutoTradeLog
		if err := rows.Scan(&l.At, &l.Level, &l.Message, &l.Code); err != nil {
			log.Printf("DB 로그 스캔 실패: %v", err)
			continue
		}
		logs = append(logs, l)
	}
	return logs
}

// --- WatchSource ---

func dbUpsertWatchSource(ws models.AutoTradeWatchSource) {
	if db == nil {
		return
	}
	themesJSON, _ := json.Marshal(ws.SelectedThemes)
	_, err := db.Exec(`INSERT INTO autotrade_watch_source (id, use_scanner, selected_themes)
		VALUES (1, $1, $2)
		ON CONFLICT (id) DO UPDATE SET use_scanner=$1, selected_themes=$2`,
		ws.UseScanner, themesJSON)
	if err != nil {
		log.Printf("DB 감시소스 저장 실패: %v", err)
	}
}

func dbLoadWatchSource() *models.AutoTradeWatchSource {
	if db == nil {
		return nil
	}
	var ws models.AutoTradeWatchSource
	var themesJSON []byte
	err := db.QueryRow(`SELECT use_scanner, selected_themes FROM autotrade_watch_source WHERE id=1`).
		Scan(&ws.UseScanner, &themesJSON)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil
		}
		log.Printf("DB 감시소스 조회 실패: %v", err)
		return nil
	}
	if err := json.Unmarshal(themesJSON, &ws.SelectedThemes); err != nil {
		ws.SelectedThemes = []models.ThemeRef{}
	}
	return &ws
}
