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

package org

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

	issues_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/issues"
	"code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/context"
)

type apiCustomFieldDef struct {
	ID          int64  `json:"id"`
	OwnerID     int64  `json:"owner_id"`
	Scope       string `json:"scope"`
	Name        string `json:"name"`
	FieldType   string `json:"field_type"`
	Description string `json:"description"`
	Options     any    `json:"options"`
	Required    bool   `json:"required"`
	SortOrder   int    `json:"sort_order"`
	IsActive    bool   `json:"is_active"`
}

func toAPIFieldDef(f *issues_model.CustomFieldDef) apiCustomFieldDef {
	var opts any
	if f.Options != "" {
		var parsed []string
		if json.Unmarshal([]byte(f.Options), &parsed) == nil {
			opts = parsed
		} else {
			opts = f.Options
		}
	}
	return apiCustomFieldDef{
		ID:          f.ID,
		OwnerID:     f.OwnerID,
		Scope:       string(f.Scope),
		Name:        f.Name,
		FieldType:   string(f.FieldType),
		Description: f.Description,
		Options:     opts,
		Required:    f.Required,
		SortOrder:   f.SortOrder,
		IsActive:    f.IsActive,
	}
}

// ListOrgCustomFields returns all custom field definitions for an org.
func ListOrgCustomFields(ctx *context.APIContext) {
	fields, err := issues_model.GetAllCustomFieldsByOwner(ctx, ctx.Org.Organization.ID)
	if err != nil {
		ctx.APIErrorInternal(err)
		return
	}
	result := make([]apiCustomFieldDef, 0, len(fields))
	for _, f := range fields {
		result = append(result, toAPIFieldDef(f))
	}
	ctx.JSON(http.StatusOK, result)
}

// CreateOrgCustomField creates a new custom field definition.
func CreateOrgCustomField(ctx *context.APIContext) {
	var req struct {
		Scope       string   `json:"scope" binding:"Required"`
		Name        string   `json:"name" binding:"Required"`
		FieldType   string   `json:"field_type" binding:"Required"`
		Description string   `json:"description"`
		Options     []string `json:"options"`
		Required    bool     `json:"required"`
		SortOrder   int      `json:"sort_order"`
	}
	if err := ctx.Req.ParseForm(); err != nil {
		ctx.APIError(http.StatusBadRequest, err)
		return
	}
	if err := json.NewDecoder(ctx.Req.Body).Decode(&req); err != nil {
		ctx.APIError(http.StatusBadRequest, err)
		return
	}
	if req.Name == "" || req.Scope == "" {
		ctx.APIError(http.StatusBadRequest, "name and scope are required")
		return
	}

	scope := issues_model.CustomFieldScope(req.Scope)
	if scope != issues_model.CustomFieldScopeIssue && scope != issues_model.CustomFieldScopeRepo {
		ctx.APIError(http.StatusBadRequest, "scope must be 'issue' or 'repo'")
		return
	}

	var optionsJSON string
	if len(req.Options) > 0 {
		data, _ := json.Marshal(req.Options)
		optionsJSON = string(data)
	}

	field := &issues_model.CustomFieldDef{
		OwnerID:     ctx.Org.Organization.ID,
		RepoID:      0,
		Scope:       scope,
		Name:        req.Name,
		FieldType:   issues_model.CustomFieldType(req.FieldType),
		Description: req.Description,
		Options:     optionsJSON,
		Required:    req.Required,
		SortOrder:   req.SortOrder,
		IsActive:    true,
	}

	if err := issues_model.CreateCustomFieldDef(ctx, field); err != nil {
		ctx.APIErrorInternal(err)
		return
	}

	ctx.JSON(http.StatusCreated, toAPIFieldDef(field))
}

// DeleteOrgCustomField deletes a custom field definition.
func DeleteOrgCustomField(ctx *context.APIContext) {
	id := ctx.PathParamInt64("id")
	field, err := issues_model.GetCustomFieldDefByID(ctx, id)
	if err != nil {
		ctx.APIErrorNotFound()
		return
	}
	if field.OwnerID != ctx.Org.Organization.ID {
		ctx.APIErrorNotFound()
		return
	}
	if err := issues_model.DeleteCustomFieldDef(ctx, id); err != nil {
		ctx.APIErrorInternal(err)
		return
	}
	ctx.Status(http.StatusNoContent)
}
