package download

import (
	"fmt"
	"honoka-chan/config"
	"honoka-chan/internal/middleware"
	"honoka-chan/internal/router"
	downloadschema "honoka-chan/internal/schema/download"
	"honoka-chan/internal/session"
	honokautils "honoka-chan/internal/utils"
	"io"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
)

const overrideServerConfigFileName = "99_0_115.zip"

func update(ctx *gin.Context) {
	ss := session.Get(ctx)
	defer ss.Finalize()

	downloadReq := downloadschema.UpdateReq{}
	err := honokautils.ParseRequestData(ctx, &downloadReq)
	if ss.CheckErr(err) {
		return
	}

	pkgList := []downloadschema.UpdateData{}
	if downloadReq.ExternalVersion != config.PackageVersion {
		pkgType := 99
		var pkgInfo []PkgInfo
		err := ss.MainEng.Table("download_m").Where("pkg_type = ? AND pkg_os = ?", pkgType, downloadReq.TargetOs).
			OrderBy("pkg_id ASC, pkg_order ASC").Find(&pkgInfo)
		if ss.CheckErr(err) {
			return
		}

		for _, pkg := range pkgInfo {
			fileName := fmt.Sprintf("%d_%d_%d.zip", pkg.PkgType, pkg.PkgID, pkg.Order)
			url := fmt.Sprintf("%s/%s/archives/%s",
				config.Conf.Settings.CdnServer, downloadReq.TargetOs, fileName)

			pkgList = append(pkgList, downloadschema.UpdateData{
				Size:    pkg.Size,
				URL:     url,
				Version: config.PackageVersion,
			})
		}

		serverConfigURL := fmt.Sprintf("%s/%s/archives/%s",
			config.Conf.Settings.CdnServer, downloadReq.TargetOs, overrideServerConfigFileName)
		serverConfigSize, ok := getRemoteFileSize(serverConfigURL)
		if ok {
			pkgList = append(pkgList, downloadschema.UpdateData{
				Size:    serverConfigSize,
				URL:     serverConfigURL,
				Version: config.PackageVersion,
			})
		}
	}

	ss.Respond(downloadschema.UpdateResp{
		ResponseData: pkgList,
		ReleaseInfo:  []any{},
		StatusCode:   200,
	})
}

func getRemoteFileSize(url string) (int, bool) {
	client := &http.Client{Timeout: 5 * time.Second}

	headReq, err := http.NewRequest(http.MethodHead, url, nil)
	if err == nil {
		if resp, err := client.Do(headReq); err == nil {
			_ = resp.Body.Close()
			if resp.StatusCode >= http.StatusOK &&
				resp.StatusCode < http.StatusMultipleChoices && resp.ContentLength > 0 {
				return int(resp.ContentLength), true
			}
		}
	}

	getResp, err := client.Get(url)
	if err != nil {
		return 0, false
	}
	defer getResp.Body.Close()
	if getResp.StatusCode < http.StatusOK || getResp.StatusCode >= http.StatusMultipleChoices {
		return 0, false
	}

	dataLen, err := io.Copy(io.Discard, getResp.Body)
	if err != nil {
		return 0, false
	}

	return int(dataLen), dataLen > 0
}

func init() {
	router.AddHandler("main.php", "POST", "/download/update", middleware.Common, update)
}
