package beatleader

import (
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"strconv"
	"time"

	"git.lxtend.com/lixiangwuxian/qqbot/sqlite3"
	"git.lxtend.com/lixiangwuxian/qqbot/util"
	_ "github.com/mattn/go-sqlite3"
)

func init() {
	createScoreTableSQL := `CREATE TABLE IF NOT EXISTS blData (
		id TEXT,
		name TEXT,
		country TEXT,
		pp REAL,
		rank INTEGER,
		country_rank INTEGER,
		total_score INTEGER,
		total_ranked_score INTEGER,
		average_ranked_accuracy REAL,
		total_play_count INTEGER,
		ranked_play_count INTEGER,
		replays_watched INTEGER,
		generated_time TEXT
	);`

	createRecordTableSQL := `CREATE TABLE IF NOT EXISTS blRecordData (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		score_id INT,
		bl_id TEXT,
		name TEXT,
		country TEXT,
		song_name VARCHAR(255),
		song_sub_name VARCHAR(255),
		song_author_name VARCHAR(255),
		song_hash VARCHAR(64),
		song_id VARCHAR(64),
		cover_image TEXT,
		difficulty_raw VARCHAR(100),
		pp REAL,
		stars REAL,
		weight REAL,
		modifiers VARCHAR(255),
		multiplier REAL,
		bad_cuts INT,
		missed_notes INT,
		max_combo INT,
		score INT,
		rank INT,
		max_score INT,
		full_combo BOOLEAN,
		device_hmd VARCHAR(100),
		device_controller_left VARCHAR(100),
		device_controller_right VARCHAR(100),
		generated_time TEXT
	);`

	sqlite3.TryCreateTable(createScoreTableSQL)
	sqlite3.TryCreateTable(createRecordTableSQL)
}

var BLQuery = &blQuery{}

type blQuery struct {
}

func (bl *blQuery) BindBL(qqId string, blId string) (reply string) {
	tx, err := sqlite3.GetTran()
	if err != nil {
		log.Print(err)
	}
	defer tx.Rollback()
	// blId为数字
	if _, isNum := strconv.Atoi(blId); isNum != nil {
		return "blId格式错误,应当为一串数字(是您的beatleader主页链接中的末尾数字部分,一般和您的steamID相同)"
	}
	data, err := FetchPlayerData(blId)
	if data == nil {
		if err != nil {
			return "请求出错，报错如下，如果确定命令没问题可以重新试试:" + err.Error()
		}
		return "未找到玩家,请检查ID后重试"
	}
	//去重
	if rows, err := tx.Query("SELECT ssid FROM ssBind WHERE qqid = ?", qqId); err == nil {
		if rows.Next() {
			var currentBlId string
			err := rows.Scan(&currentBlId)
			if err != nil {
				log.Print(err)
			}
			rows.Close()
			// 获取当前绑定账号的信息
			if currentData, err := FetchPlayerData(currentBlId); err == nil && currentData != nil {
				return fmt.Sprintf("您已绑定至bl账号：%s,请先输入\"解绑bl\"解绑", currentData.Name)
			}
			return "您已绑定过bl账号,请先输入\"解绑bl\"解绑"
		} else {
			rows.Close()
		}
	}
	if rows, err := tx.Query("SELECT * FROM ssBind WHERE ssid = ?", blId); err == nil {
		if rows.Next() {
			return "该bl账号已绑定至其他用户"
		}
		rows.Close()
	}
	_, err = tx.Exec("INSERT INTO ssBind(qqid, ssid) VALUES(?, ?)", qqId, blId)
	if err != nil {
		return "绑定失败,请稍后重试:" + err.Error()
	}
	err = tx.Commit()
	if err != nil {
		return "无法提交事务"
	}
	return "和用户名为 " + data.Name + " 的用户绑定成功，同时也绑定了您的scoresaber账号。输入\"查bl\"查看个人数据"
}

func (bl *blQuery) UnbindBL(qqId string) (reply string) {
	tx, err := sqlite3.GetTran()
	if err != nil {
		log.Print(err)
	}
	defer tx.Rollback()
	//是否已绑定
	if rows, err := tx.Query("SELECT * FROM ssBind WHERE qqid = ?", qqId); err == nil {
		if !rows.Next() {
			return "您未绑定bl账号，输入\"绑定bl [blId]\"绑定"
		}
		rows.Close()
	}
	_, err = tx.Exec("DELETE FROM ssBind WHERE qqid = ?", qqId)
	if err != nil {
		return "解绑失败"
	}
	err = tx.Commit()
	if err != nil {
		return "无法提交事务"
	}
	return "解绑成功，重新绑定请输入\"绑定bl [blId]\""
}

func (bl *blQuery) GetScore(qqId string) (currentData *PlayerDataLite, lastData *PlayerDataLite, err error) {
	db := sqlite3.GetDB() // 假设 sqlite3.GetDB() 返回 *sqlx.DB
	tx, err := db.Beginx()
	if err != nil {
		log.Print(err)
		return nil, nil, err
	}
	defer tx.Rollback()

	blId, err := getBLID(qqId)
	if err != nil {
		return nil, nil, err
	}

	// 查询玩家数据
	data, err := FetchPlayerData(blId)
	if data == nil && err == nil {
		return nil, nil, errors.New("查询出错，服务器返回了空数据")
	}
	if err != nil {
		log.Print(err)
		return nil, nil, err
	}

	// 构建 PlayerDataLite 结构体
	dataLite := data.ToDataLite()

	// 查询最近的玩家数据
	var lastDataLite PlayerDataLite
	err = tx.Get(&lastDataLite, "SELECT * FROM blData WHERE id = ? ORDER BY generated_time DESC LIMIT 1", dataLite.ID)
	if err != nil && err != sql.ErrNoRows {
		log.Print(err)
		return nil, nil, err
	}

	// 如果有新的数据，则插入
	if lastDataLite.IsDiffFrom(dataLite) {
		_, err = tx.NamedExec(`INSERT INTO blData (id, name, country, pp, rank, country_rank, total_score, 
			total_ranked_score, average_ranked_accuracy, total_play_count, ranked_play_count, replays_watched, generated_time)
			VALUES (:id, :name, :country, :pp, :rank, :country_rank, :total_score, 
			:total_ranked_score, :average_ranked_accuracy, :total_play_count, :ranked_play_count, :replays_watched, :generated_time)`, dataLite)
		if err != nil {
			log.Print(err)
			return nil, nil, err
		}

		// 提交事务
		err = tx.Commit()
		if err != nil {
			log.Print(err)
			return nil, nil, err
		}

		// 返回差异信息
		return &dataLite, &lastDataLite, nil
	}

	// 如果没有新数据，直接提交事务
	err = tx.Commit()
	if err != nil {
		log.Print(err)
		return nil, nil, err
	}

	// 返回当前数据的字符串表示
	return &dataLite, nil, nil
}

func (bl *blQuery) GetScoreWithoutUpdate(qqId string) (currentData *PlayerDataLite, err error) {
	blId, err := getBLID(qqId)
	if err != nil {
		return nil, err
	}
	// 查询玩家数据
	data, err := FetchPlayerData(blId)
	if err != nil {
		return nil, errors.New("查询出错，报错如下" + err.Error())
	}
	if data.ID == "" {
		return nil, errors.New("未找到玩家,请检查ID后重试")
	}
	dataLite := data.ToDataLite()
	// 返回当前数据的字符串表示
	return &dataLite, nil
}

func (bl *blQuery) SaveRecord(scoreData ScoreData) {
	db := sqlite3.GetDB() // 假设 sqlite3.GetDB() 返回 *sqlx.DB
	tx, err := db.Beginx()
	if err != nil {
		log.Print(err)
		return
	}
	defer tx.Rollback()

	// 创建 RecordDataLite 结构体实例
	dataLite := RecordDataLite{
		ScoreID:               scoreData.ID,
		BlID:                  scoreData.Player.ID,
		Name:                  scoreData.Player.Name,
		Country:               scoreData.Player.Country,
		SongName:              scoreData.Leaderboard.Song.Name,
		SongSubName:           scoreData.Leaderboard.Song.SubName,
		SongAuthorName:        scoreData.Leaderboard.Song.Author,
		SongHash:              scoreData.Leaderboard.Song.Hash,
		CoverImage:            scoreData.Leaderboard.Song.CoverImage,
		DifficultyRaw:         scoreData.Leaderboard.Difficulty.DifficultyName,
		Stars:                 0,
		PP:                    scoreData.Pp,
		Weight:                scoreData.Weight,
		Modifiers:             scoreData.Modifiers,
		Multiplier:            float64(scoreData.ModifiedScore) / float64(scoreData.BaseScore),
		BadCuts:               scoreData.BadCuts,
		Score:                 scoreData.ModifiedScore,
		Rank:                  scoreData.Rank,
		MaxScore:              int(float64(scoreData.ModifiedScore) / scoreData.Accuracy),
		MissedNotes:           scoreData.MissedNotes,
		MaxCombo:              scoreData.MaxCombo,
		FullCombo:             scoreData.FullCombo,
		DeviceHmd:             GetHMDStr(scoreData.HMD),
		DeviceControllerLeft:  GetControllerStr(scoreData.Controller),
		DeviceControllerRight: GetControllerStr(scoreData.Controller),
		GeneratedTime:         time.Now().Format("2006-01-02 15:04:05.999999999-07:00"),
	}
	if scoreData.Leaderboard.Difficulty.Stars != nil {
		dataLite.Stars = *scoreData.Leaderboard.Difficulty.Stars
	}

	// 使用 NamedExec 插入数据
	_, err = tx.NamedExec(`INSERT INTO blRecordData 
		(score_id, bl_id, name, country, song_name, song_sub_name, song_author_name, 
		song_hash, cover_image, difficulty_raw, pp, stars, weight, modifiers, 
		multiplier, bad_cuts, missed_notes, max_combo, score,rank, max_score, 
		full_combo, device_hmd, device_controller_left, device_controller_right, 
		generated_time) 
		VALUES (:score_id, :bl_id, :name, :country, :song_name, :song_sub_name, 
		:song_author_name, :song_hash, :cover_image, :difficulty_raw, :pp, :stars, 
		:weight, :modifiers, :multiplier, :bad_cuts, :missed_notes, :max_combo, 
		:score,:rank, :max_score, :full_combo, :device_hmd, :device_controller_left, 
		:device_controller_right, :generated_time)`, dataLite)
	if err != nil {
		log.Print(err)
		return
	}

	// 提交事务
	err = tx.Commit()
	if err != nil {
		log.Print(err)
	}
}

func (bl *blQuery) GetRecentScores(count int, qqId string) ([]RecordDataLite, error) {
	// 查询绑定的 blId
	blId, err := getBLID(qqId)
	if err != nil {
		return nil, err
	}
	// return records, nil
	playerData, err := FetchPlayerData(blId)
	if err != nil {
		return nil, err
	}
	//从线上获取
	historyUrl := "https://api.beatleader.xyz/player/%s/scores?leaderboardContext=general&page=1&sortBy=date&order=desc&includeIO=true&count=%d"
	fullUrl := fmt.Sprintf(historyUrl, blId, count)
	resp, err := http.Get(fullUrl)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	var response struct {
		Data []ScoreData `json:"data"`
	}
	err = json.Unmarshal(body, &response)
	if err != nil {
		return nil, err
	}
	scores := response.Data
	records := make([]RecordDataLite, 0)
	for _, score := range scores {
		dataLite := RecordDataLite{
			ScoreID:               score.ID,
			BlID:                  blId,
			Name:                  playerData.Name,
			Country:               playerData.Country,
			SongName:              score.Leaderboard.Song.Name,
			SongSubName:           score.Leaderboard.Song.SubName,
			SongAuthorName:        score.Leaderboard.Song.Author,
			SongHash:              score.Leaderboard.Song.Hash,
			SongId:                "",
			CoverImage:            score.Leaderboard.Song.CoverImage,
			DifficultyRaw:         score.Leaderboard.Difficulty.DifficultyName,
			PP:                    score.Pp,
			Stars:                 0,
			Weight:                score.Weight,
			Modifiers:             score.Modifiers,
			Multiplier:            float64(score.ModifiedScore) / float64(score.BaseScore),
			BadCuts:               score.BadCuts,
			Score:                 score.ModifiedScore,
			Rank:                  score.Rank,
			MaxScore:              int(float64(score.ModifiedScore) / score.Accuracy),
			FullCombo:             score.FullCombo,
			DeviceHmd:             GetHMDStr(score.HMD),
			DeviceControllerLeft:  GetControllerStr(score.Controller),
			DeviceControllerRight: GetControllerStr(score.Controller),
			GeneratedTime:         time.Unix(score.Timepost, 0).Format("2006-01-02 15:04:05.999999999-07:00"),
		}
		if score.Leaderboard.Difficulty.Stars != nil {
			dataLite.Stars = *score.Leaderboard.Difficulty.Stars
		}
		records = append(records, dataLite)
	}
	// 获取歌曲ID
	hashs := make([]string, 0)
	for _, record := range records {
		hashs = append(hashs, record.SongHash)
	}
	hashToSongId, err := util.GetSongIdsByHash(hashs)
	if err != nil {
		return nil, err
	}
	for i := 0; i < len(records); i++ {
		records[i].SongId = hashToSongId[records[i].SongHash]
	}

	return records, nil
}
