package repository

import (
	"aggios-app/backend/internal/domain"
	"database/sql"
	"fmt"
)

type SolutionRepository struct {
	db *sql.DB
}

func NewSolutionRepository(db *sql.DB) *SolutionRepository {
	return &SolutionRepository{db: db}
}

// ==================== SOLUTIONS ====================

func (r *SolutionRepository) CreateSolution(solution *domain.Solution) error {
	query := `
		INSERT INTO solutions (id, name, slug, icon, description, is_active)
		VALUES ($1, $2, $3, $4, $5, $6)
		RETURNING created_at, updated_at
	`

	return r.db.QueryRow(
		query,
		solution.ID, solution.Name, solution.Slug, solution.Icon,
		solution.Description, solution.IsActive,
	).Scan(&solution.CreatedAt, &solution.UpdatedAt)
}

func (r *SolutionRepository) GetAllSolutions() ([]domain.Solution, error) {
	query := `
		SELECT id, name, slug, icon, description, is_active, created_at, updated_at
		FROM solutions
		ORDER BY created_at DESC
	`

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

	var solutions []domain.Solution
	for rows.Next() {
		var s domain.Solution
		err := rows.Scan(
			&s.ID, &s.Name, &s.Slug, &s.Icon, &s.Description,
			&s.IsActive, &s.CreatedAt, &s.UpdatedAt,
		)
		if err != nil {
			return nil, err
		}
		solutions = append(solutions, s)
	}

	return solutions, nil
}

func (r *SolutionRepository) GetActiveSolutions() ([]domain.Solution, error) {
	query := `
		SELECT id, name, slug, icon, description, is_active, created_at, updated_at
		FROM solutions
		WHERE is_active = true
		ORDER BY name
	`

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

	var solutions []domain.Solution
	for rows.Next() {
		var s domain.Solution
		err := rows.Scan(
			&s.ID, &s.Name, &s.Slug, &s.Icon, &s.Description,
			&s.IsActive, &s.CreatedAt, &s.UpdatedAt,
		)
		if err != nil {
			return nil, err
		}
		solutions = append(solutions, s)
	}

	return solutions, nil
}

func (r *SolutionRepository) GetSolutionByID(id string) (*domain.Solution, error) {
	query := `
		SELECT id, name, slug, icon, description, is_active, created_at, updated_at
		FROM solutions
		WHERE id = $1
	`

	var s domain.Solution
	err := r.db.QueryRow(query, id).Scan(
		&s.ID, &s.Name, &s.Slug, &s.Icon, &s.Description,
		&s.IsActive, &s.CreatedAt, &s.UpdatedAt,
	)

	if err != nil {
		return nil, err
	}

	return &s, nil
}

func (r *SolutionRepository) GetSolutionBySlug(slug string) (*domain.Solution, error) {
	query := `
		SELECT id, name, slug, icon, description, is_active, created_at, updated_at
		FROM solutions
		WHERE slug = $1
	`

	var s domain.Solution
	err := r.db.QueryRow(query, slug).Scan(
		&s.ID, &s.Name, &s.Slug, &s.Icon, &s.Description,
		&s.IsActive, &s.CreatedAt, &s.UpdatedAt,
	)

	if err != nil {
		return nil, err
	}

	return &s, nil
}

func (r *SolutionRepository) UpdateSolution(solution *domain.Solution) error {
	query := `
		UPDATE solutions SET
			name = $1, slug = $2, icon = $3, description = $4, is_active = $5, updated_at = CURRENT_TIMESTAMP
		WHERE id = $6
	`

	result, err := r.db.Exec(
		query,
		solution.Name, solution.Slug, solution.Icon, solution.Description,
		solution.IsActive, solution.ID,
	)

	if err != nil {
		return err
	}

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

	if rows == 0 {
		return fmt.Errorf("solution not found")
	}

	return nil
}

func (r *SolutionRepository) DeleteSolution(id string) error {
	query := `DELETE FROM solutions WHERE id = $1`

	result, err := r.db.Exec(query, id)
	if err != nil {
		return err
	}

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

	if rows == 0 {
		return fmt.Errorf("solution not found")
	}

	return nil
}

// ==================== PLAN <-> SOLUTION ====================

func (r *SolutionRepository) AddSolutionToPlan(planID, solutionID string) error {
	query := `
		INSERT INTO plan_solutions (plan_id, solution_id)
		VALUES ($1, $2)
		ON CONFLICT (plan_id, solution_id) DO NOTHING
	`

	_, err := r.db.Exec(query, planID, solutionID)
	return err
}

func (r *SolutionRepository) RemoveSolutionFromPlan(planID, solutionID string) error {
	query := `DELETE FROM plan_solutions WHERE plan_id = $1 AND solution_id = $2`

	_, err := r.db.Exec(query, planID, solutionID)
	return err
}

func (r *SolutionRepository) GetPlanSolutions(planID string) ([]domain.Solution, error) {
	query := `
		SELECT s.id, s.name, s.slug, s.icon, s.description, s.is_active, s.created_at, s.updated_at
		FROM solutions s
		INNER JOIN plan_solutions ps ON s.id = ps.solution_id
		WHERE ps.plan_id = $1
		ORDER BY s.name
	`

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

	var solutions []domain.Solution
	for rows.Next() {
		var s domain.Solution
		err := rows.Scan(
			&s.ID, &s.Name, &s.Slug, &s.Icon, &s.Description,
			&s.IsActive, &s.CreatedAt, &s.UpdatedAt,
		)
		if err != nil {
			return nil, err
		}
		solutions = append(solutions, s)
	}

	return solutions, nil
}

func (r *SolutionRepository) SetPlanSolutions(planID string, solutionIDs []string) error {
	// Inicia transação
	tx, err := r.db.Begin()
	if err != nil {
		return err
	}

	// Remove todas as soluções antigas do plano
	_, err = tx.Exec(`DELETE FROM plan_solutions WHERE plan_id = $1`, planID)
	if err != nil {
		tx.Rollback()
		return err
	}

	// Adiciona as novas soluções
	stmt, err := tx.Prepare(`INSERT INTO plan_solutions (plan_id, solution_id) VALUES ($1, $2)`)
	if err != nil {
		tx.Rollback()
		return err
	}
	defer stmt.Close()

	for _, solutionID := range solutionIDs {
		_, err = stmt.Exec(planID, solutionID)
		if err != nil {
			tx.Rollback()
			return err
		}
	}

	return tx.Commit()
}

func (r *SolutionRepository) GetTenantSolutions(tenantID string) ([]domain.Solution, error) {
	query := `
		SELECT DISTINCT s.id, s.name, s.slug, s.icon, s.description, s.is_active, s.created_at, s.updated_at
		FROM solutions s
		INNER JOIN plan_solutions ps ON s.id = ps.solution_id
		INNER JOIN agency_subscriptions asub ON ps.plan_id = asub.plan_id
		WHERE asub.agency_id = $1 AND s.is_active = true AND asub.status = 'active'
		ORDER BY s.name
	`

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

	var solutions []domain.Solution
	for rows.Next() {
		var s domain.Solution
		err := rows.Scan(
			&s.ID, &s.Name, &s.Slug, &s.Icon, &s.Description,
			&s.IsActive, &s.CreatedAt, &s.UpdatedAt,
		)
		if err != nil {
			return nil, err
		}
		solutions = append(solutions, s)
	}

	// Se não encontrou via subscription, retorna array vazio
	if solutions == nil {
		solutions = []domain.Solution{}
	}

	return solutions, nil
}
