// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
// SPDX-License-Identifier: GPL-3.0-or-later

package updateserver

import (
	"context"
	"fmt"
	"strings"
	"time"

	"code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
	"code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/licenses"
	repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
	"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
)

// WHMCS module update JSON structures.
// WHMCS marketplace modules check for updates via a simple JSON endpoint.

type WHMCSUpdate struct {
	Name        string `json:"name"`
	Version     string `json:"version"`
	Description string `json:"description,omitempty"`
	DownloadURL string `json:"download_url,omitempty"`
	Changelog   string `json:"changelog,omitempty"`
	ReleaseDate string `json:"release_date"`
	Author      string `json:"author,omitempty"`
	AuthorURL   string `json:"author_url,omitempty"`
	SHA256      string `json:"sha256,omitempty"`
}

// GenerateWHMCSJSON builds a WHMCS-compatible module update response.
func GenerateWHMCSJSON(ctx context.Context, repo *repo_model.Repository, licenseKey string) (*WHMCSUpdate, error) {
	releases, err := db.Find[repo_model.Release](ctx, repo_model.FindReleasesOptions{
		RepoID:        repo.ID,
		ListOptions:   db.ListOptionsAll,
		IncludeDrafts: false,
		IncludeTags:   false,
	})
	if err != nil {
		return nil, fmt.Errorf("FindReleases: %w", err)
	}

	if err := repo.LoadOwner(ctx); err != nil {
		return nil, fmt.Errorf("LoadOwner: %w", err)
	}

	baseURL := strings.TrimSuffix(setting.AppURL, "/")
	repoLink := fmt.Sprintf("%s/%s/%s", baseURL, repo.Owner.Name, repo.Name)

	cfg := licenses.GetEffectiveConfig(ctx, repo.OwnerID, repo.ID)
	meta := resolveExtensionMetadata(ctx, repo, cfg)
	displayName := meta.DisplayName
	description := meta.Description
	maintainer := repo.Owner.Name
	maintainerURL := fmt.Sprintf("%s/%s", baseURL, repo.Owner.Name)
	if cfg != nil {
		if cfg.Maintainer != "" {
			maintainer = cfg.Maintainer
		}
		if cfg.MaintainerURL != "" {
			maintainerURL = cfg.MaintainerURL
		}
	}

	streams := licenses.GetEffectiveStreams(ctx, repo.OwnerID, repo.ID)

	// Find latest stable release.
	var latestStable *repo_model.Release
	for _, rel := range releases {
		if rel.IsDraft || rel.IsTag {
			continue
		}
		ch := licenses.ResolveReleaseStream(ctx, rel.ID, rel.TagName, rel.IsPrerelease, streams)
		if ch == "stable" {
			if latestStable == nil || rel.CreatedUnix > latestStable.CreatedUnix {
				latestStable = rel
			}
		}
	}

	if latestStable == nil {
		return &WHMCSUpdate{
			Name:    displayName,
			Version: "0.0.0",
		}, nil
	}

	if err := latestStable.LoadAttributes(ctx); err != nil {
		return nil, fmt.Errorf("LoadAttributes: %w", err)
	}

	var downloadURL, sha256Hash string
	for _, att := range latestStable.Attachments {
		if strings.HasSuffix(strings.ToLower(att.Name), ".zip") && !strings.HasSuffix(att.Name, ".sha256") {
			downloadURL = fmt.Sprintf("%s/releases/download/%s/%s", repoLink, latestStable.TagName, att.Name)
			break
		}
	}
	if downloadURL == "" {
		downloadURL = fmt.Sprintf("%s/archive/%s.zip", repoLink, latestStable.TagName)
	}
	if licenseKey != "" {
		downloadURL += "?dlid=" + licenseKey
	}
	for _, att := range latestStable.Attachments {
		if strings.HasSuffix(att.Name, ".sha256") {
			sha256Hash = readSHA256FromSidecar(ctx, att)
			break
		}
	}

	version := extractVersion(latestStable.TagName)
	if isStreamName(version, streams) || version == "" {
		version = extractVersion(latestStable.Title)
	}
	if version == "" {
		version = latestStable.TagName
	}

	changelog := ""
	if latestStable.Note != "" {
		changelog = latestStable.Note
	}

	return &WHMCSUpdate{
		Name:        displayName,
		Version:     version,
		Description: description,
		DownloadURL: downloadURL,
		Changelog:   changelog,
		ReleaseDate: time.Unix(int64(latestStable.CreatedUnix), 0).Format("2006-01-02"),
		Author:      maintainer,
		AuthorURL:   maintainerURL,
		SHA256:      sha256Hash,
	}, nil
}
