package repository

import (
	"database/sql"
	"time"

	"aggios-app/backend/internal/domain"

	"github.com/google/uuid"
	"github.com/lib/pq"
)

// PlanRepository handles database operations for plans
type PlanRepository struct {
	db *sql.DB
}

// NewPlanRepository creates a new plan repository
func NewPlanRepository(db *sql.DB) *PlanRepository {
	return &PlanRepository{db: db}
}

// Create creates a new plan
func (r *PlanRepository) Create(plan *domain.Plan) error {
	query := `
		INSERT INTO plans (id, name, slug, description, min_users, max_users, monthly_price, annual_price, features, differentiators, storage_gb, is_active, created_at, updated_at)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
		RETURNING id, created_at, updated_at
	`

	now := time.Now()
	plan.ID = uuid.New()
	plan.CreatedAt = now
	plan.UpdatedAt = now

	features := pq.Array(plan.Features)
	differentiators := pq.Array(plan.Differentiators)

	return r.db.QueryRow(
		query,
		plan.ID,
		plan.Name,
		plan.Slug,
		plan.Description,
		plan.MinUsers,
		plan.MaxUsers,
		plan.MonthlyPrice,
		plan.AnnualPrice,
		features,
		differentiators,
		plan.StorageGB,
		plan.IsActive,
		plan.CreatedAt,
		plan.UpdatedAt,
	).Scan(&plan.ID, &plan.CreatedAt, &plan.UpdatedAt)
}

// GetByID retrieves a plan by ID
func (r *PlanRepository) GetByID(id uuid.UUID) (*domain.Plan, error) {
	query := `
		SELECT id, name, slug, description, min_users, max_users, monthly_price, annual_price, features, differentiators, storage_gb, is_active, created_at, updated_at
		FROM plans
		WHERE id = $1
	`

	plan := &domain.Plan{}
	var features, differentiators pq.StringArray

	err := r.db.QueryRow(query, id).Scan(
		&plan.ID,
		&plan.Name,
		&plan.Slug,
		&plan.Description,
		&plan.MinUsers,
		&plan.MaxUsers,
		&plan.MonthlyPrice,
		&plan.AnnualPrice,
		&features,
		&differentiators,
		&plan.StorageGB,
		&plan.IsActive,
		&plan.CreatedAt,
		&plan.UpdatedAt,
	)

	if err != nil {
		return nil, err
	}

	plan.Features = []string(features)
	plan.Differentiators = []string(differentiators)

	return plan, nil
}

// GetBySlug retrieves a plan by slug
func (r *PlanRepository) GetBySlug(slug string) (*domain.Plan, error) {
	query := `
		SELECT id, name, slug, description, min_users, max_users, monthly_price, annual_price, features, differentiators, storage_gb, is_active, created_at, updated_at
		FROM plans
		WHERE slug = $1
	`

	plan := &domain.Plan{}
	var features, differentiators pq.StringArray

	err := r.db.QueryRow(query, slug).Scan(
		&plan.ID,
		&plan.Name,
		&plan.Slug,
		&plan.Description,
		&plan.MinUsers,
		&plan.MaxUsers,
		&plan.MonthlyPrice,
		&plan.AnnualPrice,
		&features,
		&differentiators,
		&plan.StorageGB,
		&plan.IsActive,
		&plan.CreatedAt,
		&plan.UpdatedAt,
	)

	if err != nil {
		return nil, err
	}

	plan.Features = []string(features)
	plan.Differentiators = []string(differentiators)

	return plan, nil
}

// ListAll retrieves all plans
func (r *PlanRepository) ListAll() ([]*domain.Plan, error) {
	query := `
		SELECT id, name, slug, description, min_users, max_users, monthly_price, annual_price, features, differentiators, storage_gb, is_active, created_at, updated_at
		FROM plans
		ORDER BY min_users ASC
	`

	rows, err := r.db.Query(query)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var plans []*domain.Plan

	for rows.Next() {
		plan := &domain.Plan{}
		var features, differentiators pq.StringArray

		err := rows.Scan(
			&plan.ID,
			&plan.Name,
			&plan.Slug,
			&plan.Description,
			&plan.MinUsers,
			&plan.MaxUsers,
			&plan.MonthlyPrice,
			&plan.AnnualPrice,
			&features,
			&differentiators,
			&plan.StorageGB,
			&plan.IsActive,
			&plan.CreatedAt,
			&plan.UpdatedAt,
		)

		if err != nil {
			return nil, err
		}

		plan.Features = []string(features)
		plan.Differentiators = []string(differentiators)
		plans = append(plans, plan)
	}

	return plans, rows.Err()
}

// ListActive retrieves all active plans
func (r *PlanRepository) ListActive() ([]*domain.Plan, error) {
	query := `
		SELECT id, name, slug, description, min_users, max_users, monthly_price, annual_price, features, differentiators, storage_gb, is_active, created_at, updated_at
		FROM plans
		WHERE is_active = true
		ORDER BY min_users ASC
	`

	rows, err := r.db.Query(query)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var plans []*domain.Plan

	for rows.Next() {
		plan := &domain.Plan{}
		var features, differentiators pq.StringArray

		err := rows.Scan(
			&plan.ID,
			&plan.Name,
			&plan.Slug,
			&plan.Description,
			&plan.MinUsers,
			&plan.MaxUsers,
			&plan.MonthlyPrice,
			&plan.AnnualPrice,
			&features,
			&differentiators,
			&plan.StorageGB,
			&plan.IsActive,
			&plan.CreatedAt,
			&plan.UpdatedAt,
		)

		if err != nil {
			return nil, err
		}

		plan.Features = []string(features)
		plan.Differentiators = []string(differentiators)
		plans = append(plans, plan)
	}

	return plans, rows.Err()
}

// Update updates a plan
func (r *PlanRepository) Update(plan *domain.Plan) error {
	query := `
		UPDATE plans
		SET name = $2, slug = $3, description = $4, min_users = $5, max_users = $6, monthly_price = $7, annual_price = $8, features = $9, differentiators = $10, storage_gb = $11, is_active = $12, updated_at = $13
		WHERE id = $1
		RETURNING updated_at
	`

	plan.UpdatedAt = time.Now()

	features := pq.Array(plan.Features)
	differentiators := pq.Array(plan.Differentiators)

	return r.db.QueryRow(
		query,
		plan.ID,
		plan.Name,
		plan.Slug,
		plan.Description,
		plan.MinUsers,
		plan.MaxUsers,
		plan.MonthlyPrice,
		plan.AnnualPrice,
		features,
		differentiators,
		plan.StorageGB,
		plan.IsActive,
		plan.UpdatedAt,
	).Scan(&plan.UpdatedAt)
}

// Delete deletes a plan
func (r *PlanRepository) Delete(id uuid.UUID) error {
	query := `DELETE FROM plans WHERE id = $1`
	result, err := r.db.Exec(query, id)
	if err != nil {
		return err
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		return err
	}

	if rowsAffected == 0 {
		return sql.ErrNoRows
	}

	return nil
}
