package controllers

import (
	"exhibitionCentre/base"
	"exhibitionCentre/logging"
	"exhibitionCentre/models"
	"exhibitionCentre/utils"

	"mvdan.cc/xurls/v2"
)

type EditExhibitRequest struct {
	ID int `json:"id"` // 展位id
}

type DeleteExhibitRequest struct {
	ID int `json:"id"` // 展位id
}

// 更新展品消息
type UpdateExhibitRequest struct {
	ExhibitionId int     `json:"exhibition_id"` // 展览id
	RoomIndex    int     `json:"room_index"`    // 展馆编号 1为开幕式 2为展厅 3为演播厅
	Number       int     `json:"number"`        // 展位编号
	Url          string  `json:"url"`           // 展品下载地址
	Width        float32 `json:"width"`         // 展品宽度
	Height       float32 `json:"height"`        // 展品高度
	OffsetX      float32 `json:"offset_x"`      // 展品展位横向微调
	OffsetY      float32 `json:"offset_y"`      // 展品展位纵向微调
	StayTime     int     `json:"stay_time"`     // 展品停留时间
	// 详情
	Title              string `json:"title"`               // 详情标题
	Audio              string `json:"audio"`               // 音频介绍
	Introduction       string `json:"introduction"`        // 文字介绍
	Details            string `json:"details"`             // 图文详解
	AuthorIntroduction string `json:"author_introduction"` // 作者介绍
}

func EditExhibit(router *base.Router) (int, []byte) {
	// 鉴权
	_, authorized := Authenticate(router)
	if !authorized {
		logging.Log.Error("编辑展位鉴权失败")
		return 0, nil
	}

	// 解析request数据
	var info EditExhibitRequest
	if err := utils.JsonParse(router.Data, &info); err != nil {
		logging.Log.Error("解析数据失败: ", err.Error())
		return 403, utils.SerializeErrorData("编辑展位失败!")
	}

	// 获取展位
	exhibit, err := models.GetExhibit(info.ID)
	if err != nil {
		logging.Log.Error("数据库获取展位失败: ", err.Error())
		return 403, utils.SerializeErrorData("编辑展位失败!")
	}
	return 200, utils.Serialize(exhibit)
}

func UpdateExhibit(router *base.Router) (int, []byte) {
	// 鉴权
	_, authorized := Authenticate(router)
	if !authorized {
		logging.Log.Error("编辑展位鉴权失败")
		return 0, nil
	}

	// 解析request数据
	var info UpdateExhibitRequest
	if err := utils.JsonParse(router.Data, &info); err != nil {
		logging.Log.Error("解析数据失败: ", err.Error())
		return 403, utils.SerializeErrorData("编辑展位失败!")
	}

	// 获取展览
	exhibit, _ := models.GetExhibitByNumber(info.ExhibitionId, info.RoomIndex, info.Number)
	if exhibit != nil {
		oldUrl := exhibit.Url
		oldAudio := exhibit.Audio
		oldDetails := exhibit.Details
		exhibit.ExhibitionId = uint(info.ExhibitionId)
		exhibit.RoomIndex = info.RoomIndex
		exhibit.Number = info.Number
		exhibit.Url = info.Url
		exhibit.Width = info.Width
		exhibit.Height = info.Height
		exhibit.OffsetX = info.OffsetX
		exhibit.OffsetY = info.OffsetY
		exhibit.StayTime = info.StayTime
		exhibit.Title = info.Title
		exhibit.Audio = info.Audio
		exhibit.Introduction = info.Introduction
		exhibit.Details = info.Details
		exhibit.AuthorIntroduction = info.AuthorIntroduction
		if err := models.UpdateExhibit(exhibit); err != nil {
			logging.Log.Error("数据库更新展品展位失败: ", err.Error())
			return 403, utils.SerializeErrorData("更新展位失败!")
		}
		// 检查并删除旧资源
		if oldUrl != exhibit.Url && len(oldUrl) > 0 {
			utils.DeleteAliOssFile(oldUrl)
		}
		if oldAudio != exhibit.Audio && len(oldAudio) > 0 {
			utils.DeleteAliOssFile(oldAudio)
		}
		processDetailResources(oldDetails, exhibit.Details)
	} else {
		exhibit = &models.Exhibit{
			ExhibitionId:       uint(info.ExhibitionId),
			RoomIndex:          info.RoomIndex,
			Number:             info.Number,
			Url:                info.Url,
			Width:              info.Width,
			Height:             info.Height,
			OffsetX:            info.OffsetX,
			OffsetY:            info.OffsetY,
			StayTime:           info.StayTime,
			Title:              info.Title,
			Audio:              info.Audio,
			Introduction:       info.Introduction,
			Details:            info.Details,
			AuthorIntroduction: info.AuthorIntroduction,
		}
		if err := models.CreateExhibit(exhibit); err != nil {
			logging.Log.Error("数据库创建展品展位失败: ", err.Error())
			return 403, utils.SerializeErrorData("更新展位失败!")
		}
	}
	return 200, []byte("{}")
}

func DeleteExhibit(router *base.Router) (int, []byte) {
	// 鉴权
	_, authorized := Authenticate(router)
	if !authorized {
		logging.Log.Error("删除展品鉴权失败")
		return 0, nil
	}

	// 解析request数据
	var info DeleteExhibitRequest
	if err := utils.JsonParse(router.Data, &info); err != nil {
		logging.Log.Error("解析数据失败: ", err.Error())
		return 403, utils.SerializeErrorData("删除展品失败!")
	}

	exhibit, err := models.GetExhibit(info.ID)
	if exhibit == nil {
		logging.Log.Error("数据库未查找到要删除展品失败: ", err.Error())
		return 400, utils.SerializeErrorData("删除展品失败!")
	}
	// 删除展品
	if err := models.DeleteExhibit(info.ID); err != nil {
		logging.Log.Error("数据库删除展品失败: ", err.Error())
		return 400, utils.SerializeErrorData("删除展品失败!")
	}

	// 删除oss上文件资源
	utils.DeleteAliOssFile(exhibit.Url)
	utils.DeleteAliOssFile(exhibit.Audio)
	deleteDetailResources(exhibit.Details)

	return 200, []byte("{}")
}

// 检查展品详情资源，过期则删除
func processDetailResources(oldDetailsData, newDetailsData string) {
	xurlsStrict := xurls.Strict()
	oldDetails := xurlsStrict.FindAllString(oldDetailsData, -1)
	newDetails := xurlsStrict.FindAllString(newDetailsData, -1)
	for _, o := range oldDetails {
		if !utils.StringArrayContains(newDetails, o) {
			utils.DeleteAliOssFile(o)
		}
	}
}

func deleteDetailResources(detailsData string) {
	xurlsStrict := xurls.Strict()
	details := xurlsStrict.FindAllString(detailsData, -1)
	for _, d := range details {
		utils.DeleteAliOssFile(d)
	}
}
