package imports

import (
	"context"
	"fmt"
	"fonchain-fiee/api/accountFiee"
	apiCast "fonchain-fiee/api/cast"
	"fonchain-fiee/api/files"
	"fonchain-fiee/cmd/config"
	"fonchain-fiee/pkg/model"
	modelCast "fonchain-fiee/pkg/model/cast"
	"fonchain-fiee/pkg/service"
	"fonchain-fiee/pkg/service/cast"
	"fonchain-fiee/pkg/service/upload"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

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

func ImportPublishV4(c *gin.Context) {

	excelFile, err := c.FormFile("excel")
	if err != nil {
		c.JSON(400, gin.H{"error": "缺少 Excel 文件 excel"})
		return
	}
	zipFile, err := c.FormFile("zip")
	if err != nil {
		c.JSON(400, gin.H{"error": "缺少 ZIP 文件"})
		return
	}

	tempDir := "tmp"
	os.MkdirAll(tempDir, 0755)
	excelPath := filepath.Join(tempDir, "artists.xlsx")
	zipPath := filepath.Join(tempDir, "archive.zip")
	fmt.Println("before save excel...")
	now := time.Now()

	if err = c.SaveUploadedFile(excelFile, excelPath); err != nil {
		c.JSON(500, gin.H{"error": "保存 Excel 失败"})
		return
	}
	fmt.Println("save excel success", time.Since(now))

	if err = c.SaveUploadedFile(zipFile, zipPath); err != nil {
		c.JSON(500, gin.H{"error": "保存 ZIP 文件失败"})
		return
	}
	fmt.Println("save zip success", time.Since(now))

	// 3. 解压 ZIP
	unzipPath := filepath.Join(tempDir, "unzipped")
	if _, err = os.Stat(unzipPath); err == nil {
		// 路径已存在，删除
		if removeErr := os.RemoveAll(unzipPath); removeErr != nil {
			c.JSON(500, gin.H{"error": "清理已存在解压目录失败: " + removeErr.Error()})
			return
		}
	}
	fmt.Println("开始解压...")
	os.MkdirAll(unzipPath, 0755)
	if err = archiver.Unarchive(zipPath, unzipPath); err != nil {
		c.JSON(500, gin.H{"error": "解压 ZIP 失败: " + err.Error()})
		return
	}

	entries, err := os.ReadDir(unzipPath)
	if err != nil || len(entries) == 0 {
		c.JSON(500, gin.H{"error": "读取解压目录失败或目录为空"})
		return
	}
	// 处理解压后的文件名
	if len(entries) == 1 && entries[0].IsDir() {
		// 说明解压后多了一层目录，把它设为新的 unzipPath
		unzipPath = filepath.Join(unzipPath, entries[0].Name())
	}
	defer os.RemoveAll(tempDir)

	//------------------------------------------------- 4. 读取 Excel 画家名单, 匹配视频和图片
	artists, err := readArtistVideoInfoV4(excelPath, unzipPath)
	if err != nil {
		c.JSON(500, gin.H{"error": "读取 Excel 失败"})
		return
	}
	//-----------------------------------------------------------------获取用户信息
	var failedRecords []FailedRecord
	var artistResp []ArtistVideoDetail
	fmt.Println("artists num: ", len(artists))
	for _, artist := range artists {
		var infoResp *accountFiee.UserInfoResponse
		list, err := service.AccountFieeProvider.UserList(context.Background(), &accountFiee.UserListRequest{
			Name:   artist.Name,
			SubNum: artist.SubNum,
		})
		if err != nil {
			failedRecords = append(failedRecords, FailedRecord{
				Name: artist.Name,
				Msg:  fmt.Sprintf("获取用户信息失败: %s", err.Error()),
			})
			log.Printf(fmt.Sprintf("获取用户信息失败: %s", err.Error()))
			continue
		}
		if len(list.UserList) == 0 {
			failedRecords = append(failedRecords, FailedRecord{
				Name: artist.Name,
				Msg:  fmt.Sprintf("未找到用户信息: %s", artist.Name),
			})
			log.Printf(fmt.Sprintf("未找到用户信息: %s", artist.Name))
			continue
		}
		if list != nil && len(list.UserList) > 0 {
			infoResp, err = service.AccountFieeProvider.Info(context.Background(), &accountFiee.InfoRequest{
				ID:     list.UserList[0].Id,
				Domain: "app",
			})
			if err != nil {
				failedRecords = append(failedRecords, FailedRecord{
					Name: artist.Name,
					Msg:  fmt.Sprintf("获取用户信息失败: %s", err.Error()),
				})
				log.Printf(fmt.Sprintf("获取用户信息失败: %s", err.Error()))
				continue
			}
		}

		//--------------------------------------------------检查用户视频数量
		if _, err = cast.CheckUserBundleBalance(int32(list.UserList[0].Id), modelCast.BalanceTypeVideoValue); err != nil {
			failedRecords = append(failedRecords, FailedRecord{
				Name: artist.Name,
				Msg:  fmt.Sprintf("检查用户视频可消耗数量: %s", err.Error()),
			})
			log.Printf(fmt.Sprintf("检查用户视频可消耗数量: %s", err.Error()))
			continue
		}

		//-----------------------------------------------------获取自媒体账号
		accountList, err := service.CastProvider.MediaUserList(c, &apiCast.MediaUserListReq{
			ArtistUuid: strconv.FormatUint(list.UserList[0].Id, 10),
			ArtistVal:  artist.Name,
			Page:       1,
			PageSize:   10,
		})
		if err != nil {
			failedRecords = append(failedRecords, FailedRecord{
				Name: artist.Name,
				Msg:  fmt.Sprintf("自媒体账号数量获取失败: %s,账号数量:%d", err.Error(), len(accountList.Data)),
			})
			log.Printf(fmt.Sprintf("自媒体账号数量获取失败: %s,账号数量:%d", err.Error(), len(accountList.Data)))
			continue
		}
		if accountList == nil || len(accountList.Data) == 0 {
			failedRecords = append(failedRecords, FailedRecord{
				Name: artist.Name,
				Msg:  "自媒体账号数量为0",
			})
			log.Printf(fmt.Sprintf("自媒体账号,账号数量:%d", len(accountList.Data)))
			continue
		}
		mediaAccountUuids := []string{}
		mediaAccountNames := []string{}
		platformIDs := []apiCast.PlatformIDENUM{}
		for _, info := range accountList.Data {
			if info.PlatformID == 2 && ((artist.Id == "31" && info.ArtistName == "荣小松") ||
				(artist.Id == "72" && info.ArtistName == "韩风霞")) {
				continue // 跳过
			}
			mediaAccountUuids = append(mediaAccountUuids, info.MediaAccountUuid)
			mediaAccountNames = append(mediaAccountNames, info.PlatformUserName)
			platformIDs = append(platformIDs, apiCast.PlatformIDENUM(info.PlatformID))
		}

		//---------------------------------------------------发布
		newCtx := cast.NewCtxWithUserInfo(c)
		resp, err := service.CastProvider.UpdateWorkVideo(newCtx, &apiCast.UpdateWorkVideoReq{
			Title:             artist.Title,
			Content:           artist.Title,
			VideoUrl:          artist.Video,
			CoverUrl:          artist.Img,
			AutoPublish:       apiCast.AutoPublishENUM_AutoPublish_FALSE,
			MediaAccountUuids: mediaAccountUuids,
			MediaAccountNames: mediaAccountNames,
			PlatformIDs:       platformIDs,
			PublishConfig1: &apiCast.PublishConfig{
				CanComment:    1,
				CanJoin:       1,
				CanQuote:      1,
				ForbidComment: 2,
				IsAI:          1,
				PublicType:    1,
			},
			PublishConfig2: &apiCast.PublishConfig{
				CanComment:    1,
				CanJoin:       1,
				CanQuote:      1,
				ForbidComment: 2,
				IsAI:          1,
				PublicType:    1,
			},
			PublishConfig3: &apiCast.PublishConfig{
				CanComment:    1,
				CanJoin:       1,
				CanQuote:      1,
				ForbidComment: 1,
				IsAI:          1,
				PublicType:    1,
			},
			Action:              "submit",
			ArtistUuid:          strconv.FormatUint(list.UserList[0].Id, 10),
			ArtistName:          infoResp.Name,
			ArtistPhone:         infoResp.TelNum,
			ArtistPhoneAreaCode: infoResp.TelAreaCode,
			Source:              2,
		})
		if err != nil {
			failedRecords = append(failedRecords, FailedRecord{
				Name: artist.Name,
				Msg:  fmt.Sprintf("发布"+artist.Name+"视频"+artist.Title+"失败: %s", err.Error()),
			})
			log.Printf(fmt.Sprintf("发布"+artist.Name+"视频"+artist.Title+"失败: %s", err.Error()))
			continue
		}
		artistResp = append(artistResp, ArtistVideoDetail{
			Id:         artist.Id,
			ArtistName: artist.Name,
			SubNum:     artist.SubNum,
			Title:      artist.Title,
			WorkUuid:   resp.WorkUuid,
			Youtube:    artist.Youtube,
			Instagram:  artist.Instagram,
			TikTok:     artist.TikTok,
		})
	}
	service.Success(c, map[string]interface{}{
		"failedRecords": failedRecords,
	})
}

// 读取excel 数据
func readArtistVideoInfoV4(excelPath, unzipPath string) ([]ArtistMedia, error) {
	log.Println(unzipPath)
	f, err := excelize.OpenFile(excelPath)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	sheetName := f.GetSheetName(0)
	rows, err := f.GetRows(sheetName)
	if err != nil {
		return nil, err
	}
	log.Println("start read excel")
	var artists []ArtistMedia
	for i, _ := range rows {
		id, _ := f.GetCellValue(sheetName, fmt.Sprintf("A%d", i+1))
		if id != "" {
			id = strings.TrimSpace(id)
		}
		artistName, _ := f.GetCellValue(sheetName, fmt.Sprintf("B%d", i+1))
		if artistName != "" {
			artistName = strings.TrimSpace(artistName)
		}
		PinyinName, _ := f.GetCellValue(sheetName, fmt.Sprintf("C%d", i+1))
		if PinyinName != "" {
			PinyinName = strings.TrimSpace(PinyinName)
		}
		subNum, _ := f.GetCellValue(sheetName, fmt.Sprintf("D%d", i+1))
		if subNum != "" {
			subNum = strings.TrimSpace(subNum)
		}
		PinyinFileName, _ := f.GetCellValue(sheetName, fmt.Sprintf("E%d", i+1))
		if PinyinFileName != "" {
			PinyinFileName = strings.TrimSpace(PinyinFileName)
		}
		title, _ := f.GetCellValue(sheetName, fmt.Sprintf("F%d", i+1))
		if title != "" {
			title = strings.TrimSpace(title)
		}
		artists = append(artists, ArtistMedia{
			Id:             id,
			Name:           artistName,
			Title:          title,
			PinyinName:     PinyinName,
			PinyinFileName: PinyinFileName,
			//Youtube:   youtube,
			//Instagram: instagram,
			//TikTok:    tiktok,
			SubNum: subNum,
		})
	}
	artists, err = matchArtistMediaV4(artists, unzipPath)
	return artists, nil
}

// -------------------------------------------------------上传视频图片
func matchArtistMediaV4(artists []ArtistMedia, unzipPath string) ([]ArtistMedia, error) {
	var err error
	var res []ArtistMedia
	for _, artist := range artists {
		var oldVideoPath, oldImgPath string
		//查找图片
		for _, ext := range []string{".jpg", ".png", ".jpeg"} {
			p := fmt.Sprintf("%s/%s/%s%s", unzipPath, artist.PinyinName, artist.PinyinFileName, ext)
			if _, err = os.Stat(p); err == nil {
				oldImgPath = p
				break
			}
		}
		// 不存在跳过
		if _, err = os.Stat(oldImgPath); os.IsNotExist(err) {
			fmt.Println("图片不存在: ", artist.Id, artist.Name, oldImgPath)
			continue
		}

		//查找视频
		for _, ext := range []string{".mp4", ".mov"} {
			p := fmt.Sprintf("%s/%s/%s%s", unzipPath, artist.PinyinName, artist.PinyinFileName, ext)
			if _, err = os.Stat(p); err == nil {
				oldVideoPath = p
				break
			}
		}
		//不存在跳过
		if oldVideoPath == "" {
			fmt.Println("视频不存在: ", artist.Id, artist.Name, oldVideoPath)
			continue
		}
		baseDir := filepath.Join(unzipPath, artist.Name)
		if err = os.MkdirAll(baseDir, 0755); err != nil {
			log.Println("创建目录失败:", err)
			return nil, err
		}
		log.Println("创建目录成功:", baseDir)

		// -------------------------文件重命名
		//重命名图片
		now := time.Now().Unix()
		imgPath := fmt.Sprintf("%s/%s/%s_%d.jpg", unzipPath, artist.PinyinName, artist.PinyinFileName, now)
		if err = os.Rename(oldImgPath, imgPath); err != nil {
			log.Println("图片:"+oldImgPath+"重命名失败:", err)
			return nil, err
		}
		//重命名视频
		videoPath := fmt.Sprintf("%s/%s/%s_%d.mp4", unzipPath, artist.PinyinName, artist.PinyinFileName, now)
		if err = os.Rename(oldVideoPath, videoPath); err != nil {
			log.Println("视频:"+oldVideoPath+"重命名失败:", err)
			return nil, err
		}
		//------------------------------------------------上传视频
		content, err := os.ReadFile(videoPath)
		if err != nil {
			return nil, err
		}
		if err = UploadToAnotherServiceV4(context.Background(), content, filepath.Base(videoPath)); err != nil {
			log.Println("上传视频失败:", err)
			return nil, err
		}
		var httpType string
		if config.AppConfig.System.AppMode == "dev" {
			url := "114.218.158.24:9020"
			httpType = fmt.Sprintf("%s%s", model.HttpType, url)
		} else {
			url := "saas.fiee.com"
			httpType = fmt.Sprintf("%s%s", model.HttpsType, url)
		}
		baseUrl := fmt.Sprintf("%s/api/fiee/resource/raw/", httpType)
		videoUrl := baseUrl + filepath.Base(videoPath)

		//------------------------------------------上传图片
		imgUrl, err := upload.PutBos(filepath.ToSlash(imgPath), "image", false)
		if err != nil {
			log.Println("上传图片失败:", err)
			return nil, err
		}

		//---------------------------------回填数据
		tmp := artist
		tmp.Id = artist.Id
		tmp.Name = artist.Name
		tmp.Title = artist.Title
		tmp.Img = imgUrl
		tmp.Video = filepath.ToSlash(videoUrl)
		tmp.SubNum = artist.SubNum
		res = append(res, tmp)
	}
	return res, nil
}

func UploadToAnotherServiceV4(ctx context.Context, fileData []byte, path string) error {
	const chunkSize = 4*1024*1024 - 100
	_, err := service.FilesProvider.TusCreate(ctx, &files.TusCreateReq{
		Path:          path,
		UserSpacePath: "",
		Override:      true,
	})
	if err != nil {
		return err
	}
	log.Println("create success ......**********")
	offset := int64(0)
	totalSize := int64(len(fileData))
	for offset < totalSize {
		end := offset + chunkSize
		if end > totalSize {
			end = totalSize
		}
		chunk := fileData[offset:end]
		_, err = service.FilesProvider.TusUpload(ctx, &files.TusUploadReq{
			Path:          path,
			UploadOffset:  offset,
			Content:       chunk,
			UserSpacePath: "",
		})
		if err != nil {
			return fmt.Errorf("上传 offset=%d chunk 失败: %w", offset, err)
		}
		log.Printf("upload chunk: %d - %d success\n", offset, end)
		offset = end
	}
	return nil
}
