package flags

import (
	"context"
	"database/sql"
	"errors"
	"fmt"
	"time"

	"go.uber.org/zap"
)

// PgFlagStore implements FlagStore using PostgreSQL.
type PgFlagStore struct {
	db     *sql.DB
	logger *zap.Logger
}

func NewPgFlagStore(db *sql.DB, logger *zap.Logger) *PgFlagStore {
	return &PgFlagStore{db: db, logger: logger}
}

func (p *PgFlagStore) IsEnabled(ctx context.Context, tenantID, name string) (bool, error) {
	// Tenant-specific takes precedence over global (NULL tenant_id)
	const q = `
		SELECT is_enabled FROM feature_flags
		WHERE name = $1 AND (tenant_id = $2 OR tenant_id IS NULL)
		ORDER BY tenant_id NULLS LAST
		LIMIT 1`

	var enabled bool
	err := p.db.QueryRowContext(ctx, q, name, tenantID).Scan(&enabled)
	if errors.Is(err, sql.ErrNoRows) {
		return false, nil
	}
	if err != nil {
		return false, fmt.Errorf("feature_flags is_enabled: %w", err)
	}
	return enabled, nil
}

func (p *PgFlagStore) Get(ctx context.Context, tenantID, name string) (FeatureFlag, error) {
	const q = `
		SELECT id, COALESCE(tenant_id::text,''), name, is_enabled, created_at, updated_at
		FROM feature_flags
		WHERE name = $1 AND (tenant_id = $2 OR ($2 = '' AND tenant_id IS NULL))`

	row := p.db.QueryRowContext(ctx, q, name, tenantID)
	f, err := scanFlag(row)
	if errors.Is(err, sql.ErrNoRows) {
		return FeatureFlag{}, ErrNotFound
	}
	return f, err
}

func (p *PgFlagStore) Set(ctx context.Context, tenantID, name string, enabled bool) (FeatureFlag, error) {
	// tenantID="" → NULL in DB (global flag)
	var tidArg interface{}
	if tenantID != "" {
		tidArg = tenantID
	}

	const q = `
		INSERT INTO feature_flags (tenant_id, name, is_enabled)
		VALUES ($1, $2, $3)
		ON CONFLICT (tenant_id, name) DO UPDATE
			SET is_enabled = EXCLUDED.is_enabled, updated_at = NOW()
		RETURNING id, COALESCE(tenant_id::text,''), name, is_enabled, created_at, updated_at`

	row := p.db.QueryRowContext(ctx, q, tidArg, name, enabled)
	return scanFlag(row)
}

func (p *PgFlagStore) List(ctx context.Context, tenantID string) ([]FeatureFlag, error) {
	const q = `
		SELECT id, COALESCE(tenant_id::text,''), name, is_enabled, created_at, updated_at
		FROM feature_flags
		WHERE tenant_id = $1 OR tenant_id IS NULL
		ORDER BY name`

	rows, err := p.db.QueryContext(ctx, q, tenantID)
	if err != nil {
		return nil, fmt.Errorf("feature_flags list: %w", err)
	}
	defer rows.Close() //nolint:errcheck

	var out []FeatureFlag
	for rows.Next() {
		f, err := scanFlag(rows)
		if err != nil {
			return nil, err
		}
		out = append(out, f)
	}
	return out, rows.Err()
}

func (p *PgFlagStore) Delete(ctx context.Context, tenantID, name string) error {
	var tidArg interface{}
	if tenantID != "" {
		tidArg = tenantID
	}

	const q = `DELETE FROM feature_flags WHERE name = $1 AND (tenant_id = $2 OR ($2 IS NULL AND tenant_id IS NULL))`
	res, err := p.db.ExecContext(ctx, q, name, tidArg)
	if err != nil {
		return fmt.Errorf("feature_flags delete: %w", err)
	}
	n, _ := res.RowsAffected()
	if n == 0 {
		return ErrNotFound
	}
	return nil
}

// ─── scanner ─────────────────────────────────────────────────────────────────

type flagScanner interface {
	Scan(dest ...interface{}) error
}

func scanFlag(s flagScanner) (FeatureFlag, error) {
	var (
		f         FeatureFlag
		createdAt time.Time
		updatedAt time.Time
	)
	err := s.Scan(&f.ID, &f.TenantID, &f.Name, &f.IsEnabled, &createdAt, &updatedAt)
	if err != nil {
		return FeatureFlag{}, fmt.Errorf("scanning feature_flag row: %w", err)
	}
	f.CreatedAt = createdAt
	f.UpdatedAt = updatedAt
	return f, nil
}
