package database

import (
	"context"
	"fmt"
	"time"

	"github.com/jackc/pgx/v5/pgxpool"
)

// DB wraps the pgx pool
type DB struct {
	Pool *pgxpool.Pool
}

// Connect establishes a connection to the PostgreSQL database
func Connect(databaseURL string) (*DB, error) {
	config, err := pgxpool.ParseConfig(databaseURL)
	if err != nil {
		return nil, fmt.Errorf("failed to parse database URL: %w", err)
	}

	// Configure connection pool
	config.MaxConns = 15
	config.MinConns = 3
	config.MaxConnLifetime = time.Hour
	config.MaxConnIdleTime = 30 * time.Minute
	config.HealthCheckPeriod = time.Minute

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	pool, err := pgxpool.NewWithConfig(ctx, config)
	if err != nil {
		return nil, fmt.Errorf("failed to create connection pool: %w", err)
	}

	// Test the connection
	if err := pool.Ping(ctx); err != nil {
		return nil, fmt.Errorf("failed to ping database: %w", err)
	}

	return &DB{Pool: pool}, nil
}

// Close closes the database connection pool
func (db *DB) Close() {
	db.Pool.Close()
}

// Migrate runs database migrations for the billing service
func Migrate(db *DB) error {
	ctx := context.Background()

	migrations := []string{
		// =============================================
		// Billing Service Tables
		// =============================================

		// Subscriptions - core subscription data
		`CREATE TABLE IF NOT EXISTS subscriptions (
			id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
			user_id UUID NOT NULL,
			stripe_customer_id VARCHAR(255),
			stripe_subscription_id VARCHAR(255) UNIQUE,
			plan_id VARCHAR(50) NOT NULL,
			status VARCHAR(30) NOT NULL DEFAULT 'trialing',
			trial_end TIMESTAMPTZ,
			current_period_start TIMESTAMPTZ,
			current_period_end TIMESTAMPTZ,
			cancel_at_period_end BOOLEAN DEFAULT FALSE,
			canceled_at TIMESTAMPTZ,
			ended_at TIMESTAMPTZ,
			created_at TIMESTAMPTZ DEFAULT NOW(),
			updated_at TIMESTAMPTZ DEFAULT NOW(),
			UNIQUE(user_id)
		)`,

		// Billing Plans - cached from Stripe
		`CREATE TABLE IF NOT EXISTS billing_plans (
			id VARCHAR(50) PRIMARY KEY,
			stripe_price_id VARCHAR(255) UNIQUE,
			stripe_product_id VARCHAR(255),
			name VARCHAR(100) NOT NULL,
			description TEXT,
			price_cents INT NOT NULL,
			currency VARCHAR(3) DEFAULT 'eur',
			interval VARCHAR(10) DEFAULT 'month',
			features JSONB DEFAULT '{}',
			is_active BOOLEAN DEFAULT TRUE,
			sort_order INT DEFAULT 0,
			created_at TIMESTAMPTZ DEFAULT NOW(),
			updated_at TIMESTAMPTZ DEFAULT NOW()
		)`,

		// Usage Summary - aggregated usage per period
		`CREATE TABLE IF NOT EXISTS usage_summary (
			id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
			user_id UUID NOT NULL,
			usage_type VARCHAR(50) NOT NULL,
			period_start TIMESTAMPTZ NOT NULL,
			total_count INT DEFAULT 0,
			created_at TIMESTAMPTZ DEFAULT NOW(),
			updated_at TIMESTAMPTZ DEFAULT NOW(),
			UNIQUE(user_id, usage_type, period_start)
		)`,

		// User Entitlements - cached entitlements for fast lookups
		`CREATE TABLE IF NOT EXISTS user_entitlements (
			id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
			user_id UUID NOT NULL UNIQUE,
			plan_id VARCHAR(50) NOT NULL,
			ai_requests_limit INT DEFAULT 0,
			ai_requests_used INT DEFAULT 0,
			documents_limit INT DEFAULT 0,
			documents_used INT DEFAULT 0,
			features JSONB DEFAULT '{}',
			period_start TIMESTAMPTZ,
			period_end TIMESTAMPTZ,
			created_at TIMESTAMPTZ DEFAULT NOW(),
			updated_at TIMESTAMPTZ DEFAULT NOW()
		)`,

		// Stripe Webhook Events - for idempotency
		`CREATE TABLE IF NOT EXISTS stripe_webhook_events (
			id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
			stripe_event_id VARCHAR(255) UNIQUE NOT NULL,
			event_type VARCHAR(100) NOT NULL,
			processed BOOLEAN DEFAULT FALSE,
			processed_at TIMESTAMPTZ,
			payload JSONB,
			error_message TEXT,
			created_at TIMESTAMPTZ DEFAULT NOW()
		)`,

		// Billing Audit Log
		`CREATE TABLE IF NOT EXISTS billing_audit_log (
			id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
			user_id UUID,
			action VARCHAR(50) NOT NULL,
			entity_type VARCHAR(50),
			entity_id VARCHAR(255),
			old_value JSONB,
			new_value JSONB,
			metadata JSONB,
			ip_address INET,
			user_agent TEXT,
			created_at TIMESTAMPTZ DEFAULT NOW()
		)`,

		// Invoices - cached from Stripe
		`CREATE TABLE IF NOT EXISTS invoices (
			id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
			user_id UUID NOT NULL,
			stripe_invoice_id VARCHAR(255) UNIQUE NOT NULL,
			stripe_subscription_id VARCHAR(255),
			status VARCHAR(30) NOT NULL,
			amount_due INT NOT NULL,
			amount_paid INT DEFAULT 0,
			currency VARCHAR(3) DEFAULT 'eur',
			hosted_invoice_url TEXT,
			invoice_pdf TEXT,
			period_start TIMESTAMPTZ,
			period_end TIMESTAMPTZ,
			due_date TIMESTAMPTZ,
			paid_at TIMESTAMPTZ,
			created_at TIMESTAMPTZ DEFAULT NOW()
		)`,

		// =============================================
		// Task-based Billing Tables
		// =============================================

		// Account Usage - tracks task balance per account
		`CREATE TABLE IF NOT EXISTS account_usage (
			id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
			account_id UUID NOT NULL UNIQUE,
			plan VARCHAR(50) NOT NULL,
			monthly_task_allowance INT NOT NULL,
			carryover_months_cap INT DEFAULT 5,
			max_task_balance INT NOT NULL,
			task_balance INT NOT NULL,
			last_renewal_at TIMESTAMPTZ NOT NULL,
			created_at TIMESTAMPTZ DEFAULT NOW(),
			updated_at TIMESTAMPTZ DEFAULT NOW()
		)`,

		// Tasks - individual task consumption records
		`CREATE TABLE IF NOT EXISTS tasks (
			id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
			account_id UUID NOT NULL,
			task_type VARCHAR(50) NOT NULL,
			consumed BOOLEAN DEFAULT TRUE,
			page_count INT DEFAULT 0,
			token_count INT DEFAULT 0,
			process_time INT DEFAULT 0,
			created_at TIMESTAMPTZ DEFAULT NOW()
		)`,

		// =============================================
		// Indexes
		// =============================================
		`CREATE INDEX IF NOT EXISTS idx_subscriptions_user ON subscriptions(user_id)`,
		`CREATE INDEX IF NOT EXISTS idx_subscriptions_stripe_customer ON subscriptions(stripe_customer_id)`,
		`CREATE INDEX IF NOT EXISTS idx_subscriptions_stripe_sub ON subscriptions(stripe_subscription_id)`,
		`CREATE INDEX IF NOT EXISTS idx_subscriptions_status ON subscriptions(status)`,
		`CREATE INDEX IF NOT EXISTS idx_subscriptions_trial_end ON subscriptions(trial_end)`,

		`CREATE INDEX IF NOT EXISTS idx_usage_summary_user ON usage_summary(user_id)`,
		`CREATE INDEX IF NOT EXISTS idx_usage_summary_period ON usage_summary(period_start)`,
		`CREATE INDEX IF NOT EXISTS idx_usage_summary_type ON usage_summary(usage_type)`,

		`CREATE INDEX IF NOT EXISTS idx_user_entitlements_user ON user_entitlements(user_id)`,
		`CREATE INDEX IF NOT EXISTS idx_user_entitlements_plan ON user_entitlements(plan_id)`,

		`CREATE INDEX IF NOT EXISTS idx_stripe_webhook_events_event_id ON stripe_webhook_events(stripe_event_id)`,
		`CREATE INDEX IF NOT EXISTS idx_stripe_webhook_events_type ON stripe_webhook_events(event_type)`,
		`CREATE INDEX IF NOT EXISTS idx_stripe_webhook_events_processed ON stripe_webhook_events(processed)`,

		`CREATE INDEX IF NOT EXISTS idx_billing_audit_log_user ON billing_audit_log(user_id)`,
		`CREATE INDEX IF NOT EXISTS idx_billing_audit_log_action ON billing_audit_log(action)`,
		`CREATE INDEX IF NOT EXISTS idx_billing_audit_log_created ON billing_audit_log(created_at)`,

		`CREATE INDEX IF NOT EXISTS idx_invoices_user ON invoices(user_id)`,
		`CREATE INDEX IF NOT EXISTS idx_invoices_stripe_invoice ON invoices(stripe_invoice_id)`,
		`CREATE INDEX IF NOT EXISTS idx_invoices_status ON invoices(status)`,

		`CREATE INDEX IF NOT EXISTS idx_account_usage_account ON account_usage(account_id)`,
		`CREATE INDEX IF NOT EXISTS idx_account_usage_plan ON account_usage(plan)`,
		`CREATE INDEX IF NOT EXISTS idx_account_usage_renewal ON account_usage(last_renewal_at)`,

		`CREATE INDEX IF NOT EXISTS idx_tasks_account ON tasks(account_id)`,
		`CREATE INDEX IF NOT EXISTS idx_tasks_type ON tasks(task_type)`,
		`CREATE INDEX IF NOT EXISTS idx_tasks_created ON tasks(created_at)`,

		// =============================================
		// Insert default plans
		// =============================================
		`INSERT INTO billing_plans (id, name, description, price_cents, currency, interval, features, sort_order)
		VALUES
			('basic', 'Basic', 'Perfekt für den Einstieg', 990, 'eur', 'month',
			 '{"ai_requests_limit": 300, "documents_limit": 50, "feature_flags": ["basic_ai", "basic_documents"], "max_team_members": 1, "priority_support": false, "custom_branding": false}',
			 1),
			('standard', 'Standard', 'Für regelmäßige Nutzer', 1990, 'eur', 'month',
			 '{"ai_requests_limit": 1500, "documents_limit": 200, "feature_flags": ["basic_ai", "basic_documents", "templates", "batch_processing"], "max_team_members": 3, "priority_support": false, "custom_branding": false}',
			 2),
			('premium', 'Premium', 'Für Teams und Power-User', 3990, 'eur', 'month',
			 '{"ai_requests_limit": 5000, "documents_limit": 1000, "feature_flags": ["basic_ai", "basic_documents", "templates", "batch_processing", "team_features", "admin_panel", "audit_log", "api_access"], "max_team_members": 10, "priority_support": true, "custom_branding": true}',
			 3)
		ON CONFLICT (id) DO NOTHING`,
	}

	for _, migration := range migrations {
		if _, err := db.Pool.Exec(ctx, migration); err != nil {
			return fmt.Errorf("failed to run migration: %w", err)
		}
	}

	return nil
}
