package bundle

import (
	"context"
	"errors"
	"fmt"
	"fonchain-fiee/api/bundle"
	"fonchain-fiee/pkg/model/login"
	"fonchain-fiee/pkg/service"
	"fonchain-fiee/pkg/service/bundle/common"
	"fonchain-fiee/pkg/utils"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
)

// 创建发票
func CreateBundleInvoice(c *gin.Context) {
	var req bundle.CreateInvoiceReq
	if err := c.ShouldBindJSON(&req); err != nil {
		service.Error(c, err)
		return
	}
	res, err := service.BundleProvider.CreateInvoice(context.Background(), &req)
	if err != nil {
		service.Error(c, err)
		return
	}
	service.Success(c, res)
}

// 创建纸质发票地址
func CreatePaperInvoiceAddress(c *gin.Context) {
	var req bundle.CreatePaperInvoiceAddressReq
	if err := c.ShouldBindJSON(&req); err != nil {
		service.Error(c, err)
		return
	}
	userInfo := login.GetUserInfoFromC(c)
	req.UserId = strconv.FormatInt(int64(userInfo.ID), 10)
	req.ApplyTime = time.Now().Format("2006-01-02 15:04:05")
	res, err := service.BundleProvider.CreatePaperInvoiceAddress(context.Background(), &req)
	if err != nil {
		service.Error(c, err)
		return
	}
	service.Success(c, res)
}

// 获取发票列表
func GetBundleInvoiceList(c *gin.Context) {
	var req bundle.GetInvoiceListReq
	if err := c.ShouldBindJSON(&req); err != nil {
		service.Error(c, err)
		return
	}
	res, err := service.BundleProvider.GetInvoiceList(context.Background(), &req)
	if err != nil {
		service.Error(c, err)
		return
	}
	service.Success(c, res)
}

// 获取用户信息
func GetUserInfo(c *gin.Context) {
	userInfo := login.GetUserInfoFromC(c)
	service.Success(c, userInfo)
}

// 获取纸质发票地址列表
func GetInvoiceExpressInfo(c *gin.Context) {
	var req bundle.GetInvoiceExpressInfoReq
	if err := c.ShouldBindJSON(&req); err != nil {
		service.Error(c, err)
		return
	}
	res, err := service.BundleProvider.GetInvoiceExpressInfo(context.Background(), &req)
	if err != nil {
		service.Error(c, err)
		return
	}
	service.Success(c, res)
}

// 更新纸质发票地址
func UpdateInvoiceExpressInfo(c *gin.Context) {
	var req bundle.UpdateInvoiceExpressInfoReq
	if err := c.ShouldBindJSON(&req); err != nil {
		service.Error(c, err)
		return
	}
	res, err := service.BundleProvider.UpdateInvoiceExpressInfo(context.Background(), &req)
	if err != nil {
		service.Error(c, err)
		return
	}
	service.Success(c, res)
}

// H5获取用户的发票列表
func GetInvoiceList(c *gin.Context) {
	var req bundle.GetInvoiceInfoByOrderNoReq
	if err := c.ShouldBindJSON(&req); err != nil {
		service.Error(c, err)
		return
	}
	userInfo := login.GetUserInfoFromC(c)
	req.UserId = strconv.FormatInt(int64(userInfo.ID), 10)
	res, err := service.BundleProvider.GetInvoiceInfoByOrderNo(context.Background(), &req)
	if err != nil {
		service.Error(c, err)
		return
	}
	service.Success(c, res)
}

func ExportInvoice(c *gin.Context) {
	var req bundle.GetInvoiceListReq
	if err := c.ShouldBindJSON(&req); err != nil {
		service.Error(c, err)
		return
	}
	exportFileName := "FIEE订单发票列表_" + time.Now().Format("20060102150405") + ".xlsx"

	userInfo := login.GetUserInfoFromC(c)
	filePath := fmt.Sprintf("./runtime/%d/%s", userInfo.ID, exportFileName)
	utils.CheckDirPath("./runtime/"+fmt.Sprint(userInfo.ID), true)

	res, err := service.BundleProvider.GetInvoiceList(context.Background(), &req)
	if err != nil {
		service.Error(c, errors.New(common.ExportInvoiceFailed))
		return
	}
	fmt.Println("开始写入Excel:", filePath)
	if err := writeToExcelInvoiceInfo(filePath, res.Data); err != nil {
		fmt.Println("写入Excel失败:", err)
		service.Error(c, errors.New(common.ExportInvoiceFailed))
		return
	}
	var scheme string
	if c.GetHeader("X-Forwarded-Proto") == "https" {
		scheme = "https"
	} else {
		scheme = "http"
	}

	var exportUrl string = fmt.Sprintf("%s://%s/api/fiee/static/%s", scheme, c.Request.Host, strings.Replace(filePath, "./runtime/", "", 1))
	service.Success(c, gin.H{
		"url": exportUrl,
	})
}

func writeToExcelInvoiceInfo(filePath string, data []*bundle.InvoiceInfo) error {
	f := excelize.NewFile()
	sheet := "Sheet1"

	// 手动表头（顺序与写入字段顺序必须一致）
	headers := []string{
		"是否申请纸质发票", "是否寄出", "姓名", "手机号", "国家",
		"详细地址", "申请时间", "操作艺人", "艺人编号",
	}

	// 写表头
	for i, h := range headers {
		col, _ := excelize.ColumnNumberToName(i + 1)
		cell := col + "1"
		if err := f.SetCellValue(sheet, cell, h); err != nil {
			return err
		}
	}

	// 从第2行开始写数据
	for r, it := range data {
		row := r + 2
		// 逐列写入（注意顺序必须和 headers 一致）
		write := func(colIdx int, v interface{}) error {
			col, _ := excelize.ColumnNumberToName(colIdx)
			cell := fmt.Sprintf("%s%d", col, row)
			return f.SetCellValue(sheet, cell, v)
		}
		isApplyPaperInvoice := ""
		isExpress := ""
		if it.PaperInvocieStatus == 1 {
			isApplyPaperInvoice = "未申请"
			isExpress = "未寄出"
		} else if it.PaperInvocieStatus == 2 {
			isApplyPaperInvoice = "已申请"
			isExpress = "未寄出"
		} else if it.PaperInvocieStatus == 3 {
			isApplyPaperInvoice = "已申请"
			isExpress = "已寄出"
		}

		_ = write(1, isApplyPaperInvoice)
		_ = write(2, isExpress)
		_ = write(3, it.Name)
		_ = write(4, it.Phone)
		_ = write(5, it.Country)
		_ = write(6, it.Address)
		_ = write(7, formatApplyTime(it.ApplyTime))
		_ = write(8, it.UserName)
		_ = write(9, it.UserNum)

	}

	// 可选：设置列宽，使表格更美观
	_ = f.SetColWidth(sheet, "A", "AZ", 15)

	// 保存文件
	if err := f.SaveAs(filePath); err != nil {
		return err
	}
	return nil
}

// 获取国家列表
func GetCountryList(c *gin.Context) {
	list := getCountryList()
	service.Success(c, map[string]interface{}{"data": list})
}

func getCountryList() []struct {
	Code string `json:"code"`
	Name string `json:"name"`
} {
	return []struct {
		Code string `json:"code"`
		Name string `json:"name"`
	}{
		{Code: "CN", Name: "中国"},
		{Code: "JP", Name: "日本"},
		{Code: "US", Name: "美国"},
		{Code: "HK", Name: "中国香港"},
		{Code: "MO", Name: "中国澳门"},
		{Code: "TW", Name: "中国台湾"},
		{Code: "GB", Name: "英国"},
		{Code: "KR", Name: "韩国"},
		{Code: "SG", Name: "新加坡"},
		{Code: "DE", Name: "德国"},
		{Code: "FR", Name: "法国"},
		{Code: "AU", Name: "澳大利亚"},
		{Code: "CA", Name: "加拿大"},
		{Code: "IT", Name: "意大利"},
		{Code: "ES", Name: "西班牙"},
		{Code: "NL", Name: "荷兰"},
		{Code: "BE", Name: "比利时"},
		{Code: "CH", Name: "瑞士"},
		{Code: "AT", Name: "奥地利"},
		{Code: "SE", Name: "瑞典"},
		{Code: "NO", Name: "挪威"},
		{Code: "DK", Name: "丹麦"},
		{Code: "FI", Name: "芬兰"},
		{Code: "IE", Name: "爱尔兰"},
		{Code: "PT", Name: "葡萄牙"},
		{Code: "GR", Name: "希腊"},
		{Code: "PL", Name: "波兰"},
		{Code: "CZ", Name: "捷克"},
		{Code: "HU", Name: "匈牙利"},
		{Code: "RO", Name: "罗马尼亚"},
		{Code: "RU", Name: "俄罗斯"},
		{Code: "UA", Name: "乌克兰"},
		{Code: "TR", Name: "土耳其"},
		{Code: "IL", Name: "以色列"},
		{Code: "AE", Name: "阿联酋"},
		{Code: "SA", Name: "沙特阿拉伯"},
		{Code: "IN", Name: "印度"},
		{Code: "MY", Name: "马来西亚"},
		{Code: "TH", Name: "泰国"},
		{Code: "VN", Name: "越南"},
		{Code: "PH", Name: "菲律宾"},
		{Code: "ID", Name: "印度尼西亚"},
		{Code: "NZ", Name: "新西兰"},
		{Code: "ZA", Name: "南非"},
		{Code: "EG", Name: "埃及"},
		{Code: "NG", Name: "尼日利亚"},
		{Code: "KE", Name: "肯尼亚"},
		{Code: "AR", Name: "阿根廷"},
		{Code: "BR", Name: "巴西"},
		{Code: "MX", Name: "墨西哥"},
		{Code: "CL", Name: "智利"},
		{Code: "CO", Name: "哥伦比亚"},
		{Code: "PE", Name: "秘鲁"},
		{Code: "LU", Name: "卢森堡"},
		{Code: "SK", Name: "斯洛伐克"},
		{Code: "BG", Name: "保加利亚"},
		{Code: "HR", Name: "克罗地亚"},
		{Code: "SI", Name: "斯洛文尼亚"},
		{Code: "LT", Name: "立陶宛"},
		{Code: "LV", Name: "拉脱维亚"},
		{Code: "EE", Name: "爱沙尼亚"},
		{Code: "RS", Name: "塞尔维亚"},
		{Code: "PK", Name: "巴基斯坦"},
		{Code: "BD", Name: "孟加拉国"},
		{Code: "LK", Name: "斯里兰卡"},
		{Code: "QA", Name: "卡塔尔"},
		{Code: "KW", Name: "科威特"},
		{Code: "BH", Name: "巴林"},
		{Code: "OM", Name: "阿曼"},
		{Code: "JO", Name: "约旦"},
		{Code: "LB", Name: "黎巴嫩"},
		{Code: "IR", Name: "伊朗"},
		{Code: "IQ", Name: "伊拉克"},
		{Code: "KZ", Name: "哈萨克斯坦"},
		{Code: "UZ", Name: "乌兹别克斯坦"},
		{Code: "GE", Name: "格鲁吉亚"},
		{Code: "AZ", Name: "阿塞拜疆"},
		{Code: "AM", Name: "亚美尼亚"},
		{Code: "MN", Name: "蒙古"},
		{Code: "MM", Name: "缅甸"},
		{Code: "KH", Name: "柬埔寨"},
		{Code: "LA", Name: "老挝"},
		{Code: "BN", Name: "文莱"},
		{Code: "NP", Name: "尼泊尔"},
		{Code: "AF", Name: "阿富汗"},
		{Code: "ET", Name: "埃塞俄比亚"},
		{Code: "GH", Name: "加纳"},
		{Code: "TZ", Name: "坦桑尼亚"},
		{Code: "UG", Name: "乌干达"},
		{Code: "MA", Name: "摩洛哥"},
		{Code: "TN", Name: "突尼斯"},
		{Code: "AL", Name: "阿尔巴尼亚"},
		{Code: "MK", Name: "北马其顿"},
		{Code: "BA", Name: "波黑"},
		{Code: "ME", Name: "黑山"},
		{Code: "CY", Name: "塞浦路斯"},
		{Code: "MT", Name: "马耳他"},
		{Code: "IS", Name: "冰岛"},
		{Code: "EC", Name: "厄瓜多尔"},
		{Code: "VE", Name: "委内瑞拉"},
		{Code: "CR", Name: "哥斯达黎加"},
		{Code: "PA", Name: "巴拿马"},
		{Code: "GT", Name: "危地马拉"},
		{Code: "CU", Name: "古巴"},
		{Code: "DO", Name: "多米尼加"},
		{Code: "JM", Name: "牙买加"},
		{Code: "PR", Name: "波多黎各"},
		{Code: "UY", Name: "乌拉圭"},
		{Code: "BO", Name: "玻利维亚"},
		{Code: "PY", Name: "巴拉圭"},
		{Code: "SV", Name: "萨尔瓦多"},
		{Code: "HN", Name: "洪都拉斯"},
		{Code: "NI", Name: "尼加拉瓜"},
		{Code: "TT", Name: "特立尼达和多巴哥"},
		{Code: "BS", Name: "巴哈马"},
		{Code: "BB", Name: "巴巴多斯"},
		{Code: "GY", Name: "圭亚那"},
		{Code: "SR", Name: "苏里南"},
		{Code: "BW", Name: "博茨瓦纳"},
		{Code: "ZW", Name: "津巴布韦"},
		{Code: "MZ", Name: "莫桑比克"},
		{Code: "AO", Name: "安哥拉"},
		{Code: "CM", Name: "喀麦隆"},
		{Code: "CI", Name: "科特迪瓦"},
		{Code: "SN", Name: "塞内加尔"},
		{Code: "LY", Name: "利比亚"},
		{Code: "SD", Name: "苏丹"},
		{Code: "DZ", Name: "阿尔及利亚"},
		{Code: "BY", Name: "白俄罗斯"},
		{Code: "MD", Name: "摩尔多瓦"},
	}
}

// 时间格式化函数
func formatApplyTime(s string) string {
	if s == "" {
		return s
	}
	beijing, err := time.LoadLocation("Asia/Shanghai")
	if err != nil {
		return s
	}
	layouts := []string{
		time.RFC3339, // 2026-02-03T23:01:29+08:00
		"2006-01-02 15:04:05",
		"2006-01-02T15:04:05Z07:00",
	}
	for _, layout := range layouts {
		if t, err := time.Parse(layout, s); err == nil {
			return t.In(beijing).Format("2006-01-02 15:04:05")
		}
	}
	return s
}
