// 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(IssuePriorityDef))
}

// IssuePriorityDef defines a custom issue priority at the org level.
type IssuePriorityDef 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 (IssuePriorityDef) TableName() string {
	return "issue_priority_def"
}

// GetIssuePriorityDefsByOrg returns active priority definitions for an org.
// If none exist, seeds the org with default priorities automatically.
func GetIssuePriorityDefsByOrg(ctx context.Context, orgID int64) ([]*IssuePriorityDef, error) {
	defs := make([]*IssuePriorityDef, 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 := seedDefaultIssuePriorities(ctx, orgID); err != nil {
			return defs, nil // non-fatal
		}
		return GetIssuePriorityDefsByOrg(ctx, orgID)
	}
	return defs, nil
}

// seedDefaultIssuePriorities creates the standard priority presets for an org.
func seedDefaultIssuePriorities(ctx context.Context, orgID int64) error {
	defaults := []*IssuePriorityDef{
		{OrgID: orgID, Name: "Critical", Color: "#dc2626", Description: "Requires immediate attention", SortOrder: 1, IsActive: true},
		{OrgID: orgID, Name: "High", Color: "#f97316", Description: "Should be addressed soon", SortOrder: 2, IsActive: true},
		{OrgID: orgID, Name: "Medium", Color: "#eab308", Description: "Normal priority", SortOrder: 3, IsDefault: true, IsActive: true},
		{OrgID: orgID, Name: "Low", Color: "#2563eb", Description: "Can wait", SortOrder: 4, IsActive: true},
	}
	for _, d := range defaults {
		if _, err := db.GetEngine(ctx).Insert(d); err != nil {
			return err
		}
	}
	return nil
}

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

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

// CreateIssuePriorityDef creates a new priority definition.
func CreateIssuePriorityDef(ctx context.Context, def *IssuePriorityDef) error {
	_, err := db.GetEngine(ctx).Insert(def)
	return err
}

// UpdateIssuePriorityDef updates a priority definition.
func UpdateIssuePriorityDef(ctx context.Context, def *IssuePriorityDef) error {
	_, err := db.GetEngine(ctx).ID(def.ID).AllCols().Update(def)
	return err
}

// DeleteIssuePriorityDef deletes a priority definition and clears references on issues.
func DeleteIssuePriorityDef(ctx context.Context, id int64) error {
	if _, err := db.GetEngine(ctx).Exec("UPDATE issue SET priority_id = 0 WHERE priority_id = ?", id); err != nil {
		return err
	}
	_, err := db.GetEngine(ctx).ID(id).Delete(new(IssuePriorityDef))
	return err
}

// SetIssuePriorityID updates the priority_id on an issue.
func SetIssuePriorityID(ctx context.Context, issueID, priorityID int64) error {
	_, err := db.GetEngine(ctx).Exec("UPDATE issue SET priority_id = ? WHERE id = ?", priorityID, issueID)
	return err
}
