package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"log"
	"math/rand"
	"net/http"
	"os"
	"time"
)

var seededRand = rand.New(rand.NewSource(time.Now().UnixNano()))

// 数据库结构
type Stock struct {
	ID            int       `json:"id"`
	Symbol        string    `json:"symbol"`
	Name          string    `json:"name"`
	CurrentPrice  float64   `json:"current_price"`
	Change        float64   `json:"change"`
	ChangePercent float64   `json:"change_percent"`
	MarketCap     string    `json:"market_cap"`
	PERatio       float64   `json:"pe_ratio"`
	ROE           float64   `json:"roe"`
	DebtRatio     float64   `json:"debt_ratio"`
	UpdateTime    string    `json:"update_time"`
}

type KLineData struct {
	Symbol string  `json:"symbol"`
	Date   string  `json:"date"`
	Open   float64 `json:"open"`
	High   float64 `json:"high"`
	Low    float64 `json:"low"`
	Close  float64 `json:"close"`
	Volume int64   `json:"volume"`
}

type TechnicalIndicator struct {
	ID          int       `json:"id"`
	Symbol      string    `json:"symbol"`
	Date        string    `json:"date"`
	RSI         float64   `json:"rsi"`
	MACD        float64   `json:"macd"`
	MACDSignal  float64   `json:"macd_signal"`
	MA5         float64   `json:"ma5"`
	MA10        float64   `json:"ma10"`
	MA20        float64   `json:"ma20"`
	UpdateTime  string    `json:"update_time"`
}

type Financials struct {
	ID              int       `json:"id"`
	Symbol          string    `json:"symbol"`
	Revenue         float64   `json:"revenue"`
	Profit          float64   `json:"profit"`
	ROE             float64   `json:"roe"`
	DebtToEquity    float64   `json:"debt_to_equity"`
	UpdateTime      string    `json:"update_time"`
}

// 全局变量
var db *sql.DB

func main() {
	var err error
	db, err = sql.Open("sqlite3", "./stock.db")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// 初始化数据库
	initDB()

	// 注册路由
	http.HandleFunc("/", handleIndex)
	http.HandleFunc("/api/stocks", handleGetStocks)
	http.HandleFunc("/api/stock/", handleStockDetail)
	http.HandleFunc("/api/stock/", handleKLine)
	http.HandleFunc("/api/stock/", handleIndicators)
	http.HandleFunc("/api/stock/", handleFinancials)
	http.HandleFunc("/api/search", handleSearch)
	http.HandleFunc("/api/refresh/", handleRefresh)

	// 启动服务器
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	log.Printf("🚀 服务器启动: http://localhost:%s", port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}

func initDB() {
	query := `
	CREATE TABLE IF NOT EXISTS stocks (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		symbol TEXT UNIQUE,
		name TEXT,
		current_price REAL,
		change REAL,
		change_percent REAL,
		market_cap TEXT,
		pe_ratio REAL,
		roe REAL,
		debt_ratio REAL,
		update_time TEXT
	);

	CREATE TABLE IF NOT EXISTS klines (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		symbol TEXT,
		date TEXT,
		open REAL,
		high REAL,
		low REAL,
		close REAL,
		volume INTEGER,
		FOREIGN KEY(symbol) REFERENCES stocks(symbol)
	);

	CREATE TABLE IF NOT EXISTS indicators (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		symbol TEXT,
		date TEXT,
		rsi REAL,
		macd REAL,
		macd_signal REAL,
		ma5 REAL,
		ma10 REAL,
		ma20 REAL,
		update_time TEXT,
		FOREIGN KEY(symbol) REFERENCES stocks(symbol)
	);

	CREATE TABLE IF NOT EXISTS financials (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		symbol TEXT UNIQUE,
		revenue REAL,
		profit REAL,
		roe REAL,
		debt_to_equity REAL,
		update_time TEXT
	);
	`

	_, err := db.Exec(query)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("✅ 数据库初始化成功")
}

// 主页面
func handleIndex(w http.ResponseWriter, r *http.Request) {
	// 读取HTML模板
	content, err := os.ReadFile("templates/index.html")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.Write(content)
}

// 获取股票列表
func handleGetStocks(w http.ResponseWriter, r *http.Request) {
	rows, err := db.Query("SELECT * FROM stocks ORDER BY update_time DESC")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer rows.Close()

	var stocks []Stock
	for rows.Next() {
		var s Stock
		err := rows.Scan(&s.ID, &s.Symbol, &s.Name, &s.CurrentPrice,
			&s.Change, &s.ChangePercent, &s.MarketCap,
			&s.PERatio, &s.ROE, &s.DebtRatio, &s.UpdateTime)
		if err != nil {
			continue
		}
		stocks = append(stocks, s)
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(stocks)
}

// 获取股票详情
func handleStockDetail(w http.ResponseWriter, r *http.Request) {
	symbol := r.URL.Path[len("/api/stock/"):]
	if symbol == "" {
		http.Error(w, "股票代码不能为空", http.StatusBadRequest)
		return
	}

	var stock Stock
	err := db.QueryRow(`
		SELECT * FROM stocks WHERE symbol = ?
	`, symbol).Scan(&stock.ID, &stock.Symbol, &stock.Name,
		&stock.CurrentPrice, &stock.Change, &stock.ChangePercent,
		&stock.MarketCap, &stock.PERatio, &stock.ROE, &stock.DebtRatio, &stock.UpdateTime)

	if err != nil {
		http.Error(w, "股票不存在", http.StatusNotFound)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(stock)
}

// 获取K线数据
func handleKLine(w http.ResponseWriter, r *http.Request) {
	symbol := r.URL.Path[len("/api/stock/"):]
	if symbol == "" {
		http.Error(w, "股票代码不能为空", http.StatusBadRequest)
		return
	}

	rows, err := db.Query(`
		SELECT date, open, high, low, close, volume FROM klines
		WHERE symbol = ? ORDER BY date DESC LIMIT 100
	`, symbol)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer rows.Close()

	var klines []KLineData
	for rows.Next() {
		var k KLineData
		err := rows.Scan(&k.Date, &k.Open, &k.High, &k.Low, &k.Close, &k.Volume)
		if err != nil {
			continue
		}
		klines = append(klines, k)
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(klines)
}

// 获取技术指标
func handleIndicators(w http.ResponseWriter, r *http.Request) {
	symbol := r.URL.Path[len("/api/stock/"):]
	if symbol == "" {
		http.Error(w, "股票代码不能为空", http.StatusBadRequest)
		return
	}

	rows, err := db.Query(`
		SELECT date, rsi, macd, macd_signal, ma5, ma10, ma20
		FROM indicators WHERE symbol = ? ORDER BY date DESC LIMIT 100
	`, symbol)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer rows.Close()

	var indicators []TechnicalIndicator
	for rows.Next() {
		var ind TechnicalIndicator
		err := rows.Scan(&ind.Date, &ind.RSI, &ind.MACD, &ind.MACDSignal,
			&ind.MA5, &ind.MA10, &ind.MA20)
		if err != nil {
			continue
		}
		indicators = append(indicators, ind)
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(indicators)
}

// 获取财务数据
func handleFinancials(w http.ResponseWriter, r *http.Request) {
	symbol := r.URL.Path[len("/api/stock/"):]
	if symbol == "" {
		http.Error(w, "股票代码不能为空", http.StatusBadRequest)
		return
	}

	var f Financials
	err := db.QueryRow(`
		SELECT revenue, profit, roe, debt_to_equity
		FROM financials WHERE symbol = ?
	`, symbol).Scan(&f.Revenue, &f.Profit, &f.ROE, &f.DebtToEquity)

	if err != nil {
		http.Error(w, "财务数据不存在", http.StatusNotFound)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(f)
}

// 搜索股票
func handleSearch(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query().Get("q")
	if query == "" {
		http.Error(w, "请输入搜索关键词", http.StatusBadRequest)
		return
	}

	rows, err := db.Query(`
		SELECT symbol, name, current_price, change_percent
		FROM stocks WHERE symbol LIKE ? OR name LIKE ?
		ORDER BY current_price DESC
	`, "%"+query+"%", "%"+query+"%")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer rows.Close()

	var results []map[string]interface{}
	for rows.Next() {
		var symbol, name string
		var currentPrice, changePercent float64
		err := rows.Scan(&symbol, &name, &currentPrice, &changePercent)
		if err != nil {
			continue
		}
		results = append(results, map[string]interface{}{
			"symbol":           symbol,
			"name":             name,
			"current_price":    currentPrice,
			"change_percent":   changePercent,
		})
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(results)
}

// 刷新股票数据
func handleRefresh(w http.ResponseWriter, r *http.Request) {
	symbol := r.URL.Path[len("/api/refresh/"):]
	if symbol == "" {
		http.Error(w, "股票代码不能为空", http.StatusBadRequest)
		return
	}

	// 获取yfinance数据
	stock := fetchYahooFinance(symbol)

	// 存储到数据库
	storeStockData(stock)
	storeKLineData(stock)
	storeIndicatorData(stock)

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]interface{}{
		"message":          "数据刷新成功",
		"symbol":           symbol,
		"price":            stock.CurrentPrice,
		"update_time":      time.Now().Format("2006-01-02 15:04:05"),
	})
}

// yfinance API调用（简化版）
func fetchYahooFinance(symbol string) Stock {
	// 模拟数据
	return Stock{
		Symbol:        symbol,
		Name:          getCompanyName(symbol),
		CurrentPrice:  getRandomPrice(),
		Change:        getRandomChange(),
		ChangePercent: getRandomChangePercent(),
		MarketCap:     getRandomMarketCap(),
		PERatio:       getRandomPERatio(),
		ROE:           getRandomROE(),
		DebtRatio:     getRandomDebtRatio(),
		UpdateTime:    time.Now().Format("2006-01-02 15:04:05"),
	}
}

func getCompanyName(symbol string) string {
	companies := map[string]string{
		"AAPL": "Apple Inc.",
		"MSFT": "Microsoft Corporation",
		"GOOGL": "Alphabet Inc.",
		"AMZN": "Amazon.com Inc.",
		"NVDA": "NVIDIA Corporation",
		"TSLA": "Tesla Inc.",
		"META": "Meta Platforms Inc.",
		"JPM": "JPMorgan Chase & Co.",
		"V": "Visa Inc.",
		"JNJ": "Johnson & Johnson",
	}
	if name, ok := companies[symbol]; ok {
		return name
	}
	return "Unknown Company"
}

func getRandomPrice() float64 {
	return 100 + float64(time.Now().Unix() % 500)
}

func getRandomChange() float64 {
	return (randFloat64(0,1) * 10) - 5
}

func getRandomChangePercent() float64 {
	return (randFloat64(0,1) * 10) - 5
}

func getRandomMarketCap() string {
	segments := []string{"B", "T"}
	return fmt.Sprintf("$%d%s", int(randFloat64(0,1)*1000), segments[rand.Intn(2)])
}

func getRandomPERatio() float64 {
	return 10 + randFloat64(0,1)*40
}

func getRandomROE() float64 {
	return 5 + randFloat64(0,1)*30
}

func getRandomDebtRatio() float64 {
	return 20 + randFloat64(0,1)*80
}

func storeStockData(stock Stock) error {
	_, err := db.Exec(`
		INSERT INTO stocks (symbol, name, current_price, change, change_percent, market_cap, pe_ratio, roe, debt_ratio, update_time)
		VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
		ON CONFLICT(symbol) DO UPDATE SET
			current_price = excluded.current_price,
			change = excluded.change,
			change_percent = excluded.change_percent,
			market_cap = excluded.market_cap,
			pe_ratio = excluded.pe_ratio,
			roe = excluded.roe,
			debt_ratio = excluded.debt_ratio,
			update_time = excluded.update_time
	`, stock.Symbol, stock.Name, stock.CurrentPrice, stock.Change, stock.ChangePercent,
		stock.MarketCap, stock.PERatio, stock.ROE, stock.DebtRatio, stock.UpdateTime)
	return err
}

func storeKLineData(stock Stock) error {
	for i := 0; i < 100; i++ {
		date := time.Now().AddDate(0, 0, -i).Format("2006-01-02")
		open := stock.CurrentPrice + (randFloat64(0,1)-0.5)*10
		high := open + randFloat64(0,1)*5
		low := open - randFloat64(0,1)*5
		close := open + (randFloat64(0,1)-0.5)*5
		volume := int64(randFloat64(0,1) * 1000000)

		_, err := db.Exec(`
			INSERT INTO klines (symbol, date, open, high, low, close, volume)
			VALUES (?, ?, ?, ?, ?, ?, ?)
		`, stock.Symbol, date, open, high, low, close, volume)
		if err != nil {
			return err
		}
	}
	return nil
}

func storeIndicatorData(stock Stock) error {
	for i := 0; i < 100; i++ {
		date := time.Now().AddDate(0, 0, -i).Format("2006-01-02")
		rsi := 30 + randFloat64(0,1)*40
		macd := (randFloat64(0,1) * 10) - 5
		macdSignal := macd + (randFloat64(0,1)-0.5)*2
		ma5 := stock.CurrentPrice + (randFloat64(0,1)-0.5)*5
		ma10 := stock.CurrentPrice + (randFloat64(0,1)-0.5)*8
		ma20 := stock.CurrentPrice + (randFloat64(0,1)-0.5)*12

		_, err := db.Exec(`
			INSERT INTO indicators (symbol, date, rsi, macd, macd_signal, ma5, ma10, ma20, update_time)
			VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
		`, stock.Symbol, date, rsi, macd, macdSignal, ma5, ma10, ma20,
			time.Now().Format("2006-01-02 15:04:05"))
		if err != nil {
			return err
		}
	}
	return nil
}

func randFloat64(min, max float64) float64 {
	return min + seededRand.Float64()*(max-min)
}
