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

package repo

import (
	"context"

	"code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
	"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil"
)

func init() {
	db.RegisterModel(new(RepoManifest))
}

// RepoManifest stores mokoplatform manifest settings for a repository.
// These fields correspond to the .mokogitea/manifest.xml schema and are
// exposed via API for use by Actions workflows and the mokoplatform CLI.
type RepoManifest struct {
	ID        int64              `xorm:"pk autoincr"`
	RepoID    int64              `xorm:"UNIQUE INDEX NOT NULL 'repo_id'"`

	// identity section
	Name        string `xorm:"TEXT 'name'"`         // project name
	Org         string `xorm:"TEXT 'org'"`           // organization name
	Description string `xorm:"TEXT 'description'"`   // project description
	Version     string `xorm:"TEXT 'version'"`       // current version string
	LicenseSPDX string `xorm:"VARCHAR(50) 'license_spdx'"` // SPDX identifier, e.g. "GPL-3.0-or-later"
	LicenseName string `xorm:"TEXT 'license_name'"`  // human-readable license name

	// governance section
	Platform         string `xorm:"VARCHAR(50) 'platform'"`          // go, php, node, python, etc.
	StandardsVersion string `xorm:"VARCHAR(20) 'standards_version'"` // mokoplatform standards version
	StandardsSource  string `xorm:"TEXT 'standards_source'"`          // URL to standards repo

	// versioning
	VersionPrefix string `xorm:"TEXT 'version_prefix'"`  // tag prefix stripped for version display, e.g. "v1.26.1-moko."
	ElementName   string `xorm:"TEXT 'element_name'"`    // full element name override, e.g. "pkg_mokowaas" (auto-constructed if empty)

	// distribution metadata (used by update server feed generation)
	DisplayName   string `xorm:"TEXT 'display_name'"`    // human-readable name for update feeds, e.g. "Package - MokoWaaS"
	Maintainer    string `xorm:"TEXT 'maintainer'"`      // maintainer/author name
	MaintainerURL string `xorm:"TEXT 'maintainer_url'"`  // maintainer website
	InfoURL       string `xorm:"TEXT 'info_url'"`        // extension info/product page URL
	TargetVersion string `xorm:"TEXT 'target_version'"`  // target platform version regex, e.g. "(5|6)\..*"
	PHPMinimum    string `xorm:"VARCHAR(20) 'php_minimum'"` // minimum PHP version, e.g. "8.1"

	// build section
	Language    string `xorm:"VARCHAR(50) 'language'"`     // Go, PHP, TypeScript, etc.
	PackageType string `xorm:"VARCHAR(50) 'package_type'"` // application, library, plugin, module, component, package
	EntryPoint  string `xorm:"TEXT 'entry_point'"`          // build entry point path

	CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED 'created_unix'"`
	UpdatedUnix timeutil.TimeStamp `xorm:"UPDATED 'updated_unix'"`
}

func (RepoManifest) TableName() string {
	return "repo_manifest"
}

// joomlaTypePrefix maps Joomla extension types to their element name prefixes.
var joomlaTypePrefix = map[string]string{
	"component": "com_",
	"module":    "mod_",
	"plugin":    "plg_",
	"package":   "pkg_",
	"template":  "tpl_",
	"library":   "lib_",
	"file":      "file_",
}

// AutoElementName returns the auto-constructed Joomla element name (e.g. pkg_mokowaas).
func (m *RepoManifest) AutoElementName() string {
	if m.Name == "" || m.PackageType == "" {
		return ""
	}
	if prefix, ok := joomlaTypePrefix[m.PackageType]; ok {
		return prefix + m.Name
	}
	return m.Name
}

// FullElementName returns the effective element name: override if set, otherwise auto-constructed.
func (m *RepoManifest) FullElementName() string {
	if m.ElementName != "" {
		return m.ElementName
	}
	return m.AutoElementName()
}

// ElementNameMismatch returns true if an override is set that differs from the auto-constructed name.
func (m *RepoManifest) ElementNameMismatch() bool {
	if m.ElementName == "" {
		return false
	}
	auto := m.AutoElementName()
	return auto != "" && m.ElementName != auto
}

// GetRepoManifest returns the manifest for a repo, or nil if none exists.
func GetRepoManifest(ctx context.Context, repoID int64) (*RepoManifest, error) {
	m := new(RepoManifest)
	has, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Get(m)
	if err != nil {
		return nil, err
	}
	if !has {
		return nil, nil
	}
	return m, nil
}

// CreateOrUpdateRepoManifest upserts a repo manifest.
func CreateOrUpdateRepoManifest(ctx context.Context, m *RepoManifest) error {
	existing := new(RepoManifest)
	has, err := db.GetEngine(ctx).Where("repo_id = ?", m.RepoID).Get(existing)
	if err != nil {
		return err
	}
	if has {
		m.ID = existing.ID
		_, err = db.GetEngine(ctx).ID(m.ID).AllCols().Update(m)
		return err
	}
	_, err = db.GetEngine(ctx).Insert(m)
	return err
}

// DeleteRepoManifest deletes the manifest for a repo.
func DeleteRepoManifest(ctx context.Context, repoID int64) error {
	_, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Delete(new(RepoManifest))
	return err
}
