package douyin

import (
	"bindbox-game/internal/pkg/logger"
	"bindbox-game/internal/repository/mysql"
	"bindbox-game/internal/repository/mysql/dao"
	"bindbox-game/internal/repository/mysql/model"
	"bindbox-game/internal/service/game"
	"bindbox-game/internal/service/sysconfig"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"go.uber.org/zap"
)

// 系统配置键
const (
	ConfigKeyDouyinCookie   = "douyin_cookie"
	ConfigKeyDouyinInterval = "douyin_sync_interval_minutes"
)

type Service interface {
	// FetchAndSyncOrders 从抖店 API 获取订单并同步到本地
	FetchAndSyncOrders(ctx context.Context) (*SyncResult, error)
	// ListOrders 获取本地抖店订单列表
	ListOrders(ctx context.Context, page, pageSize int, status *int) ([]*model.DouyinOrders, int64, error)
	// GetConfig 获取抖店配置
	GetConfig(ctx context.Context) (*DouyinConfig, error)
	// SaveConfig 保存抖店配置
	SaveConfig(ctx context.Context, cookie string, intervalMinutes int) error
	// SyncOrder 同步单个订单到本地，可传入建议关联的用户ID
	SyncOrder(ctx context.Context, item *DouyinOrderItem, suggestUserID int64) (isNew bool, isMatched bool)
}

type DouyinConfig struct {
	Cookie          string `json:"cookie"`
	IntervalMinutes int    `json:"interval_minutes"`
}

type SyncResult struct {
	TotalFetched int `json:"total_fetched"`
	NewOrders    int `json:"new_orders"`
	MatchedUsers int `json:"matched_users"`
}

type service struct {
	logger    logger.CustomLogger
	repo      mysql.Repo
	readDB    *dao.Query
	writeDB   *dao.Query
	syscfg    sysconfig.Service
	ticketSvc game.TicketService
}

func New(l logger.CustomLogger, repo mysql.Repo, syscfg sysconfig.Service, ticketSvc game.TicketService) Service {
	return &service{
		logger:    l,
		repo:      repo,
		readDB:    dao.Use(repo.GetDbR()),
		writeDB:   dao.Use(repo.GetDbW()),
		syscfg:    syscfg,
		ticketSvc: ticketSvc,
	}
}

// GetConfig 获取抖店配置
func (s *service) GetConfig(ctx context.Context) (*DouyinConfig, error) {
	cfg := &DouyinConfig{IntervalMinutes: 5}

	if c, err := s.syscfg.GetByKey(ctx, ConfigKeyDouyinCookie); err == nil && c != nil {
		cfg.Cookie = c.ConfigValue
	}
	if c, err := s.syscfg.GetByKey(ctx, ConfigKeyDouyinInterval); err == nil && c != nil {
		if v, e := strconv.Atoi(c.ConfigValue); e == nil && v > 0 {
			cfg.IntervalMinutes = v
		}
	}
	return cfg, nil
}

// SaveConfig 保存抖店配置
func (s *service) SaveConfig(ctx context.Context, cookie string, intervalMinutes int) error {
	if _, err := s.syscfg.UpsertByKey(ctx, ConfigKeyDouyinCookie, cookie, "抖店Cookie"); err != nil {
		return err
	}
	if intervalMinutes < 1 {
		intervalMinutes = 5
	}
	if _, err := s.syscfg.UpsertByKey(ctx, ConfigKeyDouyinInterval, strconv.Itoa(intervalMinutes), "抖店订单同步间隔(分钟)"); err != nil {
		return err
	}
	return nil
}

// ListOrders 获取本地抖店订单列表
func (s *service) ListOrders(ctx context.Context, page, pageSize int, status *int) ([]*model.DouyinOrders, int64, error) {
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 20
	}

	db := s.repo.GetDbR().WithContext(ctx).Model(&model.DouyinOrders{})
	if status != nil {
		db = db.Where("order_status = ?", *status)
	}

	var total int64
	if err := db.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	var orders []*model.DouyinOrders
	if err := db.Order("id DESC").Offset((page - 1) * pageSize).Limit(pageSize).Find(&orders).Error; err != nil {
		return nil, 0, err
	}

	return orders, total, nil
}

// FetchAndSyncOrders 遍历所有已绑定抖音号的用户并同步其订单
func (s *service) FetchAndSyncOrders(ctx context.Context) (*SyncResult, error) {
	cfg, err := s.GetConfig(ctx)
	if err != nil {
		return nil, fmt.Errorf("获取配置失败: %w", err)
	}
	if cfg.Cookie == "" {
		return nil, fmt.Errorf("抖店 Cookie 未配置")
	}

	// 1. 获取所有绑定了抖音号的用户
	var users []model.Users
	if err := s.repo.GetDbR().WithContext(ctx).Where("douyin_user_id != ''").Find(&users).Error; err != nil {
		return nil, fmt.Errorf("获取绑定用户失败: %w", err)
	}

	result := &SyncResult{}
	fmt.Printf("[DEBUG] 开始全量同步，共 %d 个绑定用户\n", len(users))

	// 2. 遍历用户，按 buyer 抓取订单
	for _, u := range users {
		fmt.Printf("[DEBUG] 正在同步用户 ID: %d (昵称: %s, 抖音号: %s) 的订单...\n", u.ID, u.Nickname, u.DouyinUserID)

		orders, err := s.fetchDouyinOrdersByBuyer(cfg.Cookie, u.DouyinUserID)
		if err != nil {
			fmt.Printf("[DEBUG] 抓取用户 %s 订单失败: %v\n", u.DouyinUserID, err)
			continue
		}

		result.TotalFetched += len(orders)

		// 3. 同步
		for _, order := range orders {
			// 同步订单（传入建议关联的用户 ID）
			isNew, matched := s.SyncOrder(ctx, &order, u.ID)
			if isNew {
				result.NewOrders++
			}
			if matched {
				result.MatchedUsers++
			}
		}
	}

	s.logger.Info("[抖店同步] 全量同步完成",
		zap.Int("users_count", len(users)),
		zap.Int("total_fetched", result.TotalFetched),
		zap.Int("new_orders", result.NewOrders),
		zap.Int("matched_users", result.MatchedUsers),
	)

	return result, nil
}

// 抖店 API 响应结构
type douyinOrderResponse struct {
	Code int               `json:"code"`
	St   int               `json:"st"` // 抖店实际返回的是 st 而非 code
	Msg  string            `json:"msg"`
	Data []DouyinOrderItem `json:"data"` // data 直接是数组
}

type DouyinOrderItem struct {
	ShopOrderID         string `json:"shop_order_id"`
	OrderStatus         int    `json:"order_status"`
	UserID              string `json:"user_id"`
	ActualReceiveAmount string `json:"actual_receive_amount"`
	PayTypeDesc         string `json:"pay_type_desc"`
	Remark              string `json:"remark"`
	UserNickname        string `json:"user_nickname"`
}

// fetchDouyinOrdersByBuyer 调用抖店 API 按 Buyer ID 获取订单
func (s *service) fetchDouyinOrdersByBuyer(cookie string, buyer string) ([]DouyinOrderItem, error) {
	// 拼接带有业务标识的搜索 URL
	baseUrl := "https://fxg.jinritemai.com/api/order/searchlist"
	params := url.Values{}
	params.Set("page", "0")
	params.Set("pageSize", "100")
	params.Set("buyer", buyer)
	params.Set("order_by", "create_time")
	params.Set("order", "desc")
	params.Set("tab", "all")
	params.Set("appid", "1")
	params.Set("_bid", "ffa_order")
	params.Set("aid", "4272")

	fullUrl := baseUrl + "?" + params.Encode()

	req, err := http.NewRequest("GET", fullUrl, nil)
	if err != nil {
		return nil, err
	}

	// 设置请求头
	req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36")
	req.Header.Set("Accept", "application/json, text/plain, */*")
	req.Header.Set("Cookie", cookie)
	req.Header.Set("Referer", "https://fxg.jinritemai.com/ffa/morder/order/list")

	client := &http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	var respData douyinOrderResponse
	if err := json.Unmarshal(body, &respData); err != nil {
		s.logger.Error("[抖店API] 解析响应失败", zap.String("response", string(body[:min(len(body), 500)])))
		return nil, fmt.Errorf("解析响应失败: %w", err)
	}

	if respData.St != 0 && respData.Code != 0 {
		return nil, fmt.Errorf("API 返回错误: %s", respData.Msg)
	}

	return respData.Data, nil
}

// SyncOrder 同步单个订单到本地
func (s *service) SyncOrder(ctx context.Context, item *DouyinOrderItem, suggestUserID int64) (isNew bool, isMatched bool) {
	db := s.repo.GetDbW().WithContext(ctx)

	var order model.DouyinOrders
	err := db.Where("shop_order_id = ?", item.ShopOrderID).First(&order).Error

	if err == nil {
		// 订单已存在
		isNew = false
		// 只有当订单还没关联用户，且提供了建议用户时，才做关联
		if (order.LocalUserID == "" || order.LocalUserID == "0") && suggestUserID > 0 {
			order.LocalUserID = strconv.FormatInt(suggestUserID, 10)
			db.Model(&order).Update("local_user_id", order.LocalUserID)
			fmt.Printf("[DEBUG] 抖店辅助关联成功: %s -> User %d\n", item.ShopOrderID, suggestUserID)
		}

		// 更新状态
		db.Model(&order).Updates(map[string]any{
			"order_status": item.OrderStatus,
			"remark":       item.Remark,
		})
		// 重要：同步内存状态，防止后续判断逻辑失效
		order.OrderStatus = int32(item.OrderStatus)
		order.Remark = item.Remark
	} else {
		// 订单不存在，创建新记录
		isNew = true
		localUserIDStr := "0"
		if suggestUserID > 0 {
			localUserIDStr = strconv.FormatInt(suggestUserID, 10)
		}

		fmt.Printf("[DEBUG] 抖店新订单: %s, UserID: %s, Recommend: %s\n", item.ShopOrderID, item.UserID, localUserIDStr)

		// 解析金额
		var amount int64
		if item.ActualReceiveAmount != "" {
			if f, err := strconv.ParseFloat(strings.TrimSpace(item.ActualReceiveAmount), 64); err == nil {
				amount = int64(f * 100)
			}
		}
		rawData, _ := json.Marshal(item)

		order = model.DouyinOrders{
			ShopOrderID:         item.ShopOrderID,
			OrderStatus:         int32(item.OrderStatus),
			DouyinUserID:        item.UserID,
			ActualReceiveAmount: amount,
			PayTypeDesc:         item.PayTypeDesc,
			Remark:              item.Remark,
			UserNickname:        item.UserNickname,
			RawData:             string(rawData),
			RewardGranted:       0,
			LocalUserID:         localUserIDStr,
		}

		if err := db.Create(&order).Error; err != nil {
			s.logger.Error("[抖店同步] 创建订单失败", zap.String("shop_order_id", item.ShopOrderID), zap.Error(err))
			return false, false
		}
	}

	// 如果还没关联用户（比如之前全量抓取的），尝试用抖店的 UID (long string) 匹配
	if (order.LocalUserID == "" || order.LocalUserID == "0") && item.UserID != "" {
		var user model.Users
		if err := s.repo.GetDbR().Where("douyin_user_id = ?", item.UserID).First(&user).Error; err == nil {
			order.LocalUserID = strconv.FormatInt(user.ID, 10)
			db.Model(&order).Update("local_user_id", order.LocalUserID)
			fmt.Printf("[DEBUG] 通过抖店 UID 匹配成功: User %d\n", user.ID)
		}
	}

	// ---- 统一处理：发放奖励 ----
	isMatched = order.LocalUserID != "" && order.LocalUserID != "0"
	if isMatched && order.RewardGranted == 0 && order.OrderStatus == 5 {
		localUserID, _ := strconv.ParseInt(order.LocalUserID, 10, 64)
		fmt.Printf("[DEBUG] 准备发放奖励: User: %d, ShopOrder: %s\n", localUserID, item.ShopOrderID)

		if localUserID > 0 && s.ticketSvc != nil {
			err := s.ticketSvc.GrantTicket(ctx, localUserID, "minesweeper", 1, "douyin_order", order.ID, "抖店订单奖励")
			if err == nil {
				db.Model(&order).Update("reward_granted", 1)
				order.RewardGranted = 1
				fmt.Printf("[DEBUG] 订单 %s 发放奖励成功\n", item.ShopOrderID)
			} else {
				fmt.Printf("[DEBUG] 订单 %s 发放奖励失败: %v\n", item.ShopOrderID, err)
			}
		}
	}

	return isNew, isMatched
}

// min 返回两个整数的最小值
func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}
