package sqlite

import (
	"context"
	"database/sql"

	"chat-switchboard/models"
	"chat-switchboard/store"
)

type PricingStore struct{}

func NewPricingStore() *PricingStore { return &PricingStore{} }

// GetForModel returns the pricing entry for a specific provider+model pair.
func (s *PricingStore) GetForModel(ctx context.Context, providerConfigID, modelID string) (*models.PricingEntry, error) {
	var p models.PricingEntry
	err := DB.QueryRowContext(ctx, `
		SELECT id, provider_config_id, model_id,
		       input_per_m, output_per_m, cache_create_per_m, cache_read_per_m,
		       currency, source, updated_at, updated_by
		FROM model_pricing
		WHERE provider_config_id = ? AND model_id = ?
	`, providerConfigID, modelID).Scan(
		&p.ID, &p.ProviderConfigID, &p.ModelID,
		&p.InputPerM, &p.OutputPerM, &p.CacheCreatePerM, &p.CacheReadPerM,
		&p.Currency, &p.Source, st(&p.UpdatedAt), &p.UpdatedBy,
	)
	if err == sql.ErrNoRows {
		return nil, nil
	}
	return &p, err
}

// Upsert inserts or updates a pricing entry (manual admin override).
func (s *PricingStore) Upsert(ctx context.Context, entry *models.PricingEntry) error {
	_, err := DB.ExecContext(ctx, `
		INSERT INTO model_pricing (
			id, provider_config_id, model_id,
			input_per_m, output_per_m, cache_create_per_m, cache_read_per_m,
			currency, source, updated_by, updated_at
		) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))
		ON CONFLICT (provider_config_id, model_id)
		DO UPDATE SET
			input_per_m = EXCLUDED.input_per_m,
			output_per_m = EXCLUDED.output_per_m,
			cache_create_per_m = EXCLUDED.cache_create_per_m,
			cache_read_per_m = EXCLUDED.cache_read_per_m,
			currency = EXCLUDED.currency,
			source = EXCLUDED.source,
			updated_by = EXCLUDED.updated_by,
			updated_at = datetime('now')
	`,
		store.NewID(), entry.ProviderConfigID, entry.ModelID,
		entry.InputPerM, entry.OutputPerM, entry.CacheCreatePerM, entry.CacheReadPerM,
		entry.Currency, entry.Source, entry.UpdatedBy,
	)
	return err
}

// UpsertFromCatalog inserts or updates pricing from a catalog sync.
// Manual overrides (source='manual') are never overwritten.
func (s *PricingStore) UpsertFromCatalog(ctx context.Context, providerConfigID, modelID string, pricing *models.ModelPricing) error {
	if pricing == nil || (pricing.InputPerM == 0 && pricing.OutputPerM == 0) {
		return nil // No pricing to store
	}

	currency := pricing.Currency
	if currency == "" {
		currency = "USD"
	}

	_, err := DB.ExecContext(ctx, `
		INSERT INTO model_pricing (
			id, provider_config_id, model_id,
			input_per_m, output_per_m,
			currency, source, updated_at
		) VALUES (?, ?, ?, ?, ?, ?, 'catalog', datetime('now'))
		ON CONFLICT (provider_config_id, model_id)
		DO UPDATE SET
			input_per_m = EXCLUDED.input_per_m,
			output_per_m = EXCLUDED.output_per_m,
			currency = EXCLUDED.currency,
			updated_at = datetime('now')
		WHERE model_pricing.source = 'catalog'
	`,
		store.NewID(), providerConfigID, modelID,
		pricing.InputPerM, pricing.OutputPerM,
		currency,
	)
	return err
}

// List returns pricing entries for admin-managed providers (global + team).
// Excludes personal BYOK providers — those are not the admin's concern.
func (s *PricingStore) List(ctx context.Context) ([]models.PricingEntry, error) {
	rows, err := DB.QueryContext(ctx, `
		SELECT mp.id, mp.provider_config_id, mp.model_id,
		       mp.input_per_m, mp.output_per_m, mp.cache_create_per_m, mp.cache_read_per_m,
		       mp.currency, mp.source, mp.updated_at, mp.updated_by
		FROM model_pricing mp
		JOIN provider_configs pc ON pc.id = mp.provider_config_id
		WHERE pc.scope != 'personal'
		ORDER BY mp.provider_config_id, mp.model_id
	`)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var results []models.PricingEntry
	for rows.Next() {
		var p models.PricingEntry
		if err := rows.Scan(
			&p.ID, &p.ProviderConfigID, &p.ModelID,
			&p.InputPerM, &p.OutputPerM, &p.CacheCreatePerM, &p.CacheReadPerM,
			&p.Currency, &p.Source, st(&p.UpdatedAt), &p.UpdatedBy,
		); err != nil {
			return nil, err
		}
		results = append(results, p)
	}
	return results, rows.Err()
}

// Delete removes a pricing entry.
func (s *PricingStore) Delete(ctx context.Context, providerConfigID, modelID string) error {
	_, err := DB.ExecContext(ctx, `
		DELETE FROM model_pricing WHERE provider_config_id = ? AND model_id = ?
	`, providerConfigID, modelID)
	return err
}
