package seatbilling

import (
	"context"
	"fmt"
	"strings"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/store/storeerr"
)

func (store *Store) LoadSubscription(ctx context.Context, organizationID string) (SeatSubscription, bool, error) {
	db, err := store.requireDB()
	if err != nil {
		return SeatSubscription{}, false, err
	}
	return loadSubscription(ctx, db, organizationID, false)
}

func (store *Store) LoadEffectiveEntitlement(ctx context.Context, organizationID string, now time.Time) (SeatEntitlement, error) {
	db, err := store.requireDB()
	if err != nil {
		return SeatEntitlement{}, err
	}
	return LoadEffectiveEntitlement(ctx, db, organizationID, now, false)
}

// LoadEffectiveEntitlement resolves the billing seat entitlement for one
// organization using queryer. When lock is true, the effective subscription row
// is selected FOR UPDATE for callers already inside a mutation transaction.
func LoadEffectiveEntitlement(ctx context.Context, queryer coredb.QueryRower, organizationID string, now time.Time, lock bool) (SeatEntitlement, error) {
	trimmedOrganizationID := strings.TrimSpace(organizationID)
	if trimmedOrganizationID == "" {
		return SeatEntitlement{}, storeerr.BadRequest("organizationId is required")
	}
	if now.IsZero() {
		now = time.Now().UTC()
	}
	now = now.UTC()
	giftSeats, nextGrantExpiresAt, err := loadActiveSeatGrantSummary(ctx, queryer, trimmedOrganizationID, now)
	if err != nil {
		return SeatEntitlement{}, err
	}
	subscription, found, err := loadEffectiveSubscription(ctx, queryer, trimmedOrganizationID, now, lock)
	if err != nil {
		return SeatEntitlement{}, err
	}
	if !found {
		return SeatEntitlement{
			OrganizationID:         trimmedOrganizationID,
			PlanKey:                "free",
			HumanSeatLimit:         FreeHumanSeatLimit + giftSeats,
			FreeHumanSeatLimit:     FreeHumanSeatLimit,
			GiftHumanSeatLimit:     giftSeats,
			NextGrantExpiresAt:     nextGrantExpiresAt,
			OrganizationAgentLimit: FreeAgentsPerHumanOwnerLimit,
			ManagedAgentsPerSeat:   FreeAgentsPerHumanOwnerLimit,
			Paid:                   false,
		}, nil
	}
	start := subscription.CurrentPeriodStart
	end := subscription.CurrentPeriodEnd
	paidSeats := int64(subscription.SeatQuantity)
	seatLimit := FreeHumanSeatLimit + paidSeats + giftSeats
	return SeatEntitlement{
		OrganizationID:         trimmedOrganizationID,
		PlanKey:                subscription.PlanKey,
		BillingPeriod:          subscription.BillingPeriod,
		HumanSeatLimit:         seatLimit,
		FreeHumanSeatLimit:     FreeHumanSeatLimit,
		PaidHumanSeatLimit:     paidSeats,
		GiftHumanSeatLimit:     giftSeats,
		NextGrantExpiresAt:     nextGrantExpiresAt,
		OrganizationAgentLimit: subscription.ManagedAgentsPerSeatSnapshot,
		ManagedAgentsPerSeat:   subscription.ManagedAgentsPerSeatSnapshot,
		CurrentPeriodStart:     &start,
		CurrentPeriodEnd:       &end,
		Paid:                   true,
		SubscriptionStatus:     subscription.Status,
	}, nil
}

func loadSubscription(ctx context.Context, queryer coredb.QueryRower, organizationID string, lock bool) (SeatSubscription, bool, error) {
	trimmedOrganizationID := strings.TrimSpace(organizationID)
	if trimmedOrganizationID == "" {
		return SeatSubscription{}, false, storeerr.BadRequest("organizationId is required")
	}
	lockClause := ""
	if lock {
		lockClause = " FOR UPDATE"
	}
	subscription, err := scanSeatSubscription(queryer.QueryRow(ctx, `
SELECT
  organization_id,
  status,
  plan_key,
  billing_period,
  seat_quantity,
  managed_agents_per_seat_snapshot,
  max_human_seats_snapshot,
  unit_price_cents_snapshot,
  currency,
  current_period_start,
  current_period_end,
  created_at,
  updated_at
FROM organization_seat_subscriptions
WHERE organization_id = $1
`+lockClause, trimmedOrganizationID))
	if err != nil {
		if coredb.IsNotFound(err) {
			return SeatSubscription{}, false, nil
		}
		return SeatSubscription{}, false, err
	}
	return subscription, true, nil
}

func loadEffectiveSubscription(ctx context.Context, queryer coredb.QueryRower, organizationID string, now time.Time, lock bool) (SeatSubscription, bool, error) {
	trimmedOrganizationID := strings.TrimSpace(organizationID)
	if trimmedOrganizationID == "" {
		return SeatSubscription{}, false, storeerr.BadRequest("organizationId is required")
	}
	lockClause := ""
	if lock {
		lockClause = " FOR UPDATE"
	}
	subscription, err := scanSeatSubscription(queryer.QueryRow(ctx, `
SELECT
  organization_id,
  status,
  plan_key,
  billing_period,
  seat_quantity,
  managed_agents_per_seat_snapshot,
  max_human_seats_snapshot,
  unit_price_cents_snapshot,
  currency,
  current_period_start,
  current_period_end,
  created_at,
  updated_at
FROM organization_seat_subscriptions
WHERE organization_id = $1
  AND status = 'active'
  AND current_period_start <= $2
  AND $2 < current_period_end
`+lockClause, trimmedOrganizationID, now.UTC()))
	if err != nil {
		if coredb.IsNotFound(err) {
			return SeatSubscription{}, false, nil
		}
		return SeatSubscription{}, false, err
	}
	return subscription, true, nil
}

type seatSubscriptionScanner interface {
	Scan(...any) error
}

func scanSeatSubscription(scanner seatSubscriptionScanner) (SeatSubscription, error) {
	var subscription SeatSubscription
	if err := scanner.Scan(
		&subscription.OrganizationID,
		&subscription.Status,
		&subscription.PlanKey,
		&subscription.BillingPeriod,
		&subscription.SeatQuantity,
		&subscription.ManagedAgentsPerSeatSnapshot,
		&subscription.MaxHumanSeatsSnapshot,
		&subscription.UnitPriceCentsSnapshot,
		&subscription.Currency,
		&subscription.CurrentPeriodStart,
		&subscription.CurrentPeriodEnd,
		&subscription.CreatedAt,
		&subscription.UpdatedAt,
	); err != nil {
		return SeatSubscription{}, fmt.Errorf("scan seat subscription: %w", err)
	}
	return subscription, nil
}
