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

package licensing

import (
	"context"

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

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

// LicenseEntitlement maps a license to an individual product (repo) it can access.
type LicenseEntitlement struct {
	ID          int64              `xorm:"pk autoincr"`
	LicenseID   int64              `xorm:"INDEX NOT NULL"`
	ProductCode string             `xorm:"VARCHAR(30) NOT NULL"`
	RepoOwner   string             `xorm:"VARCHAR(100) NOT NULL DEFAULT 'MokoConsulting'"`
	RepoName    string             `xorm:"VARCHAR(100) NOT NULL"`
	IsCustom    bool               `xorm:"NOT NULL DEFAULT false"` // true = manually added, survives tier changes
	CreatedAt   timeutil.TimeStamp `xorm:"CREATED"`
}

func (LicenseEntitlement) TableName() string {
	return "license_entitlement"
}

// GetEntitlementsByLicense returns all entitlements for a license.
func GetEntitlementsByLicense(ctx context.Context, licenseID int64) ([]*LicenseEntitlement, error) {
	var ents []*LicenseEntitlement
	return ents, db.GetEngine(ctx).Where("license_id = ?", licenseID).Find(&ents)
}

// HasEntitlement checks if a license has access to a specific product code.
func HasEntitlement(ctx context.Context, licenseID int64, productCode string) (bool, error) {
	return db.GetEngine(ctx).
		Where("license_id = ? AND product_code = ?", licenseID, productCode).
		Exist(new(LicenseEntitlement))
}

// AddCustomEntitlement adds a manual entitlement that survives tier changes.
func AddCustomEntitlement(ctx context.Context, licenseID int64, productCode, repoName string) error {
	ent := &LicenseEntitlement{
		LicenseID:   licenseID,
		ProductCode: productCode,
		RepoOwner:   "MokoConsulting",
		RepoName:    repoName,
		IsCustom:    true,
	}
	_, err := db.GetEngine(ctx).Insert(ent)
	return err
}

// RebuildEntitlements deletes non-custom entitlements and rebuilds from the product tier.
// Custom entitlements (manually added) are preserved.
func RebuildEntitlements(ctx context.Context, licenseID int64, tierKey string) error {
	// Delete non-custom entitlements
	_, err := db.GetEngine(ctx).
		Where("license_id = ? AND is_custom = ?", licenseID, false).
		Delete(new(LicenseEntitlement))
	if err != nil {
		return err
	}

	// Look up tier
	tier, err := GetProductTierByKey(ctx, tierKey)
	if err != nil || tier == nil {
		return err
	}

	// Parse repos JSON
	var repos []string
	if err := json.Unmarshal([]byte(tier.Repos), &repos); err != nil {
		return err
	}

	// Build product code from repo name (lowercase, stripped)
	for _, repoName := range repos {
		productCode := repoName
		// Check if this entitlement already exists (custom)
		exists, err := db.GetEngine(ctx).
			Where("license_id = ? AND product_code = ?", licenseID, productCode).
			Exist(new(LicenseEntitlement))
		if err != nil {
			return err
		}
		if exists {
			continue
		}

		ent := &LicenseEntitlement{
			LicenseID:   licenseID,
			ProductCode: productCode,
			RepoOwner:   "MokoConsulting",
			RepoName:    repoName,
			IsCustom:    false,
		}
		if _, err := db.GetEngine(ctx).Insert(ent); err != nil {
			return err
		}
	}

	return nil
}
