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

package setting

import (
	"encoding/json"
	"fmt"
	"net/http"

	issues_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/issues"
	repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
	updateserver_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/updateserver"
	"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/templates"
	"code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/context"
)

const tplSettingsMetadata templates.TplName = "repo/settings/metadata"

// Metadata displays the consolidated metadata page:
// project identity (manifest), update server config, and repo-scoped custom fields.
func Metadata(ctx *context.Context) {
	ctx.Data["Title"] = "Metadata"
	ctx.Data["PageIsSettingsMetadata"] = true

	repoID := ctx.Repo.Repository.ID
	ownerID := ctx.Repo.Repository.OwnerID

	// Load manifest (project identity).
	manifest, err := repo_model.GetRepoManifest(ctx, repoID)
	if err != nil {
		ctx.ServerError("GetRepoManifest", err)
		return
	}
	if manifest == nil {
		manifest = &repo_model.RepoManifest{
			RepoID:      repoID,
			Name:        ctx.Repo.Repository.Name,
			Org:         ctx.Repo.Repository.OwnerName,
			Description: ctx.Repo.Repository.Description,
		}
	}
	ctx.Data["Manifest"] = manifest

	// Load update server config.
	repoCfg, _ := updateserver_model.GetRepoConfig(ctx, repoID)
	ctx.Data["RepoUpdateConfig"] = repoCfg

	// Load repo-scoped custom fields.
	fields, _ := issues_model.GetCustomFieldsByOwner(ctx, ownerID, issues_model.CustomFieldScopeRepo)
	ctx.Data["CustomFieldDefs"] = fields

	values := make(map[int64]string)
	fieldOptions := make(map[int64][]string)
	if len(fields) > 0 {
		values, _ = issues_model.GetCustomFieldValuesMap(ctx, repoID)
		for _, f := range fields {
			if f.Options != "" {
				var opts []string
				if err := json.Unmarshal([]byte(f.Options), &opts); err == nil {
					fieldOptions[f.ID] = opts
				}
			}
		}
	}
	ctx.Data["CustomFieldValues"] = values
	ctx.Data["CustomFieldOptions"] = fieldOptions

	ctx.HTML(http.StatusOK, tplSettingsMetadata)
}

// MetadataPost routes to the correct sub-handler based on the action param.
func MetadataPost(ctx *context.Context) {
	switch ctx.FormString("action") {
	case "manifest":
		saveManifest(ctx)
	case "customfields":
		saveCustomFields(ctx)
	default:
		saveManifest(ctx)
	}
}

func saveManifest(ctx *context.Context) {
	manifest := &repo_model.RepoManifest{
		RepoID:           ctx.Repo.Repository.ID,
		Name:             ctx.FormString("name"),
		Org:              ctx.FormString("org"),
		Description:      ctx.Repo.Repository.Description,
		Version:          ctx.FormString("version"),
		LicenseSPDX:      ctx.FormString("license_spdx"),
		LicenseName:      ctx.FormString("license_name"),
		VersionPrefix:    ctx.FormString("version_prefix"),
		ElementName:      ctx.FormString("element_name"),
		Platform:         ctx.FormString("platform"),
		StandardsVersion: ctx.FormString("standards_version"),
		StandardsSource:  ctx.FormString("standards_source"),
		DisplayName:      ctx.FormString("display_name"),
		Maintainer:       ctx.FormString("maintainer"),
		MaintainerURL:    ctx.FormString("maintainer_url"),
		InfoURL:          ctx.FormString("info_url"),
		TargetVersion:    ctx.FormString("target_version"),
		PHPMinimum:       ctx.FormString("php_minimum"),
		Language:         ctx.FormString("language"),
		PackageType:      ctx.FormString("package_type"),
		EntryPoint:       ctx.FormString("entry_point"),
	}

	if err := repo_model.CreateOrUpdateRepoManifest(ctx, manifest); err != nil {
		ctx.ServerError("CreateOrUpdateRepoManifest", err)
		return
	}

	ctx.Flash.Success("Project identity saved")
	ctx.Redirect(ctx.Repo.RepoLink + "/settings/metadata")
}

func saveCustomFields(ctx *context.Context) {
	repoID := ctx.Repo.Repository.ID
	ownerID := ctx.Repo.Repository.OwnerID

	fields, _ := issues_model.GetCustomFieldsByOwner(ctx, ownerID, issues_model.CustomFieldScopeRepo)
	for _, f := range fields {
		val := ctx.Req.FormValue(fmt.Sprintf("field_%d", f.ID))
		if err := issues_model.SetCustomFieldValue(ctx, repoID, f.ID, val); err != nil {
			ctx.ServerError("SetCustomFieldValue", err)
			return
		}
	}

	ctx.Flash.Success("Custom fields saved")
	ctx.Redirect(ctx.Repo.RepoLink + "/settings/metadata")
}

