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

package issues

import (
	"context"

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

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

// IssueTypeDef defines a custom issue type at the org level.
type IssueTypeDef struct {
	ID          int64              `xorm:"pk autoincr"`
	OrgID       int64              `xorm:"INDEX NOT NULL DEFAULT 0 'org_id'"`
	Name        string             `xorm:"NOT NULL"`
	Color       string             `xorm:"VARCHAR(7)"`
	Description string             `xorm:"TEXT"`
	SortOrder   int                `xorm:"NOT NULL DEFAULT 0 'sort_order'"`
	IsDefault   bool               `xorm:"NOT NULL DEFAULT false 'is_default'"`
	IsActive    bool               `xorm:"NOT NULL DEFAULT true 'is_active'"`
	CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED 'created_unix'"`
	UpdatedUnix timeutil.TimeStamp `xorm:"UPDATED 'updated_unix'"`
}

func (IssueTypeDef) TableName() string {
	return "issue_type_def"
}

// GetIssueTypeDefsByOrg returns active type definitions for an org.
// Auto-seeds defaults if none exist.
func GetIssueTypeDefsByOrg(ctx context.Context, orgID int64) ([]*IssueTypeDef, error) {
	defs := make([]*IssueTypeDef, 0, 10)
	if err := db.GetEngine(ctx).
		Where("org_id = ? AND is_active = ?", orgID, true).
		OrderBy("sort_order ASC, id ASC").
		Find(&defs); err != nil {
		return nil, err
	}
	if len(defs) == 0 && orgID > 0 {
		if err := seedDefaultIssueTypes(ctx, orgID); err != nil {
			return defs, nil
		}
		return GetIssueTypeDefsByOrg(ctx, orgID)
	}
	return defs, nil
}

// GetAllIssueTypeDefsByOrg returns all type definitions (including inactive).
func GetAllIssueTypeDefsByOrg(ctx context.Context, orgID int64) ([]*IssueTypeDef, error) {
	defs := make([]*IssueTypeDef, 0, 10)
	return defs, db.GetEngine(ctx).
		Where("org_id = ?", orgID).
		OrderBy("sort_order ASC, id ASC").
		Find(&defs)
}

// GetIssueTypeDefByID returns a single type definition.
func GetIssueTypeDefByID(ctx context.Context, id int64) (*IssueTypeDef, error) {
	def := new(IssueTypeDef)
	has, err := db.GetEngine(ctx).ID(id).Get(def)
	if err != nil {
		return nil, err
	}
	if !has {
		return nil, db.ErrNotExist{Resource: "IssueTypeDef", ID: id}
	}
	return def, nil
}

func CreateIssueTypeDef(ctx context.Context, def *IssueTypeDef) error {
	_, err := db.GetEngine(ctx).Insert(def)
	return err
}

func UpdateIssueTypeDef(ctx context.Context, def *IssueTypeDef) error {
	_, err := db.GetEngine(ctx).ID(def.ID).AllCols().Update(def)
	return err
}

func DeleteIssueTypeDef(ctx context.Context, id int64) error {
	if _, err := db.GetEngine(ctx).Exec("UPDATE issue SET type_id = 0 WHERE type_id = ?", id); err != nil {
		return err
	}
	_, err := db.GetEngine(ctx).ID(id).Delete(new(IssueTypeDef))
	return err
}

func SetIssueTypeID(ctx context.Context, issueID, typeID int64) error {
	_, err := db.GetEngine(ctx).Exec("UPDATE issue SET type_id = ? WHERE id = ?", typeID, issueID)
	return err
}

func seedDefaultIssueTypes(ctx context.Context, orgID int64) error {
	defaults := []*IssueTypeDef{
		{OrgID: orgID, Name: "Bug", Color: "#dc2626", SortOrder: 1, IsActive: true},
		{OrgID: orgID, Name: "Feature", Color: "#2563eb", SortOrder: 2, IsDefault: true, IsActive: true},
		{OrgID: orgID, Name: "Enhancement", Color: "#16a34a", SortOrder: 3, IsActive: true},
		{OrgID: orgID, Name: "Task", Color: "#6b7280", SortOrder: 4, IsActive: true},
		{OrgID: orgID, Name: "Documentation", Color: "#8b5cf6", SortOrder: 5, IsActive: true},
		{OrgID: orgID, Name: "Security", Color: "#e11d48", SortOrder: 6, IsActive: true},
	}
	for _, d := range defaults {
		if _, err := db.GetEngine(ctx).Insert(d); err != nil {
			return err
		}
	}
	return nil
}
