package controlplane

import (
	"context"
	"database/sql"
	"fmt"
	"log"
	"strings"

	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/pingcap-inc/nexuscrm-controlplane/packs"
)

func RemovePackOwnedField(ctx context.Context, r *Runner, packName string, objectAPIName string, fieldAPIName string) error {
	return withControlPlaneMutationLock(ctx, r.DB.DB(), "RemovePackOwnedField", func() error {
		return removePackOwnedFieldUnlocked(ctx, r, packName, objectAPIName, fieldAPIName)
	})
}

func removePackOwnedFieldUnlocked(ctx context.Context, r *Runner, packName string, objectAPIName string, fieldAPIName string) error {
	if r == nil || r.DB == nil || r.SvcMgr == nil || r.SvcMgr.Schema() == nil {
		return fmt.Errorf("control-plane schema manager is unavailable")
	}
	packName = strings.TrimSpace(packName)
	objectAPIName = strings.TrimSpace(objectAPIName)
	fieldAPIName = strings.TrimSpace(fieldAPIName)
	if packName == "" || objectAPIName == "" || fieldAPIName == "" {
		return fmt.Errorf("remove-pack-owned-field requires pack, object, and field names")
	}
	preflight, err := loadPackOwnedFieldRemovalPreflight(ctx, r.DB.DB(), objectAPIName, fieldAPIName)
	if err != nil {
		return err
	}
	if preflight.ownerPack != packName {
		return fmt.Errorf("field %s.%s OwnerPack = %q, want %q", objectAPIName, fieldAPIName, preflight.ownerPack, packName)
	}
	if preflight.ownerKind != constants.FieldOwnerKindPack &&
		preflight.ownerKind != constants.FieldOwnerKindPackRetained &&
		preflight.ownerKind != constants.FieldOwnerKindPackRemoving {
		return fmt.Errorf("field %s.%s OwnerKind = %q, want pack, pack_retained, or pack_removing", objectAPIName, fieldAPIName, preflight.ownerKind)
	}
	active, err := packs.IsPackActive(ctx, r.DB.DB(), packName)
	if err != nil {
		return err
	}
	if !active {
		return fmt.Errorf("installed pack %s is not active", packName)
	}
	declared, err := packs.IsFieldDeclaredByCurrentSourceForExplicitRemovalWithComponentKindRegistrationSet(
		ctx, r.DB.DB(), packName, objectAPIName, fieldAPIName, r.componentKindRegistrationSet(),
	)
	if err != nil {
		return err
	}
	if declared {
		return fmt.Errorf("installed pack %s still declares field %s.%s", packName, objectAPIName, fieldAPIName)
	}
	if err := r.SvcMgr.Schema().DropColumnPhase1(objectAPIName, fieldAPIName, packName); err != nil {
		return err
	}
	if err := r.SvcMgr.Schema().DropColumnPhase2(objectAPIName, fieldAPIName, packName); err != nil {
		return err
	}
	if err := r.RefreshCache(ctx); err != nil {
		log.Printf("controlplane: pack-owned field %s.%s removed for %s, but metadata cache refresh failed after phase2: %v", objectAPIName, fieldAPIName, packName, err)
	}
	return nil
}

type packOwnedFieldRemovalPreflight struct {
	ownerKind string
	ownerPack string
}

func loadPackOwnedFieldRemovalPreflight(ctx context.Context, db *sql.DB, objectAPIName string, fieldAPIName string) (packOwnedFieldRemovalPreflight, error) {
	objectAPIName = strings.TrimSpace(objectAPIName)
	fieldAPIName = strings.TrimSpace(fieldAPIName)
	if objectAPIName == "" || fieldAPIName == "" {
		return packOwnedFieldRemovalPreflight{}, fmt.Errorf("pack-owned field removal preflight requires object and field names")
	}
	var row packOwnedFieldRemovalPreflight
	err := db.QueryRowContext(ctx, `
SELECT COALESCE(f.OwnerKind, ''), COALESCE(f.OwnerPack, '')
FROM _System_Field f
JOIN _System_Object o ON o.Id = f.ObjectId
WHERE o.ApiName = ? AND f.ApiName = ?
LIMIT 1`, objectAPIName, fieldAPIName).Scan(&row.ownerKind, &row.ownerPack)
	if err == sql.ErrNoRows {
		return packOwnedFieldRemovalPreflight{}, fmt.Errorf("field %s.%s is missing", objectAPIName, fieldAPIName)
	}
	if err != nil {
		return packOwnedFieldRemovalPreflight{}, fmt.Errorf("query field %s.%s removal preflight: %w", objectAPIName, fieldAPIName, err)
	}
	row.ownerKind = strings.TrimSpace(row.ownerKind)
	row.ownerPack = strings.TrimSpace(row.ownerPack)
	return row, nil
}
