// 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/timeutil"
)

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

// LicenseActivation tracks a domain that has activated a license.
type LicenseActivation struct {
	ID          int64              `xorm:"pk autoincr"`
	LicenseID   int64              `xorm:"INDEX NOT NULL"`
	Domain      string             `xorm:"VARCHAR(255) NOT NULL"`
	IPAddress   string             `xorm:"VARCHAR(64)"`
	JoomlaVer   string             `xorm:"VARCHAR(20)"`
	ActivatedAt timeutil.TimeStamp `xorm:"CREATED"`
	LastSeenAt  timeutil.TimeStamp
}

func (LicenseActivation) TableName() string {
	return "license_activation"
}

// GetActivationsByLicense returns all domain activations for a license.
func GetActivationsByLicense(ctx context.Context, licenseID int64) ([]*LicenseActivation, error) {
	var acts []*LicenseActivation
	return acts, db.GetEngine(ctx).Where("license_id = ?", licenseID).Find(&acts)
}

// CountActivations returns the number of activated domains for a license.
func CountActivations(ctx context.Context, licenseID int64) (int64, error) {
	return db.GetEngine(ctx).Where("license_id = ?", licenseID).Count(new(LicenseActivation))
}

// ActivateDomain registers a domain for a license. Returns the activation
// (existing or new) and whether it was newly created.
func ActivateDomain(ctx context.Context, licenseID int64, domain, ip, joomlaVer string, maxDomains int) (*LicenseActivation, bool, error) {
	// Check if already activated
	existing := new(LicenseActivation)
	has, err := db.GetEngine(ctx).
		Where("license_id = ? AND domain = ?", licenseID, domain).
		Get(existing)
	if err != nil {
		return nil, false, err
	}
	if has {
		// Update last seen
		existing.LastSeenAt = timeutil.TimeStampNow()
		existing.IPAddress = ip
		if joomlaVer != "" {
			existing.JoomlaVer = joomlaVer
		}
		_, _ = db.GetEngine(ctx).ID(existing.ID).Cols("last_seen_at", "ip_address", "joomla_ver").Update(existing)
		return existing, false, nil
	}

	// Check domain limit (0 = unlimited)
	if maxDomains > 0 {
		count, err := CountActivations(ctx, licenseID)
		if err != nil {
			return nil, false, err
		}
		if count >= int64(maxDomains) {
			return nil, false, ErrDomainLimitReached{LicenseID: licenseID, Max: maxDomains}
		}
	}

	act := &LicenseActivation{
		LicenseID: licenseID,
		Domain:    domain,
		IPAddress: ip,
		JoomlaVer: joomlaVer,
	}
	_, err = db.GetEngine(ctx).Insert(act)
	if err != nil {
		return nil, false, err
	}
	return act, true, nil
}

// DeactivateDomain removes a domain activation.
func DeactivateDomain(ctx context.Context, licenseID int64, domain string) error {
	_, err := db.GetEngine(ctx).
		Where("license_id = ? AND domain = ?", licenseID, domain).
		Delete(new(LicenseActivation))
	return err
}

// ErrDomainLimitReached is returned when a license has reached its max activated domains.
type ErrDomainLimitReached struct {
	LicenseID int64
	Max       int
}

func (e ErrDomainLimitReached) Error() string {
	return "license domain limit reached"
}
