package service

import (
	"database/sql"
	"errors"

	"aggios-app/backend/internal/domain"
	"aggios-app/backend/internal/repository"

	"github.com/google/uuid"
)

var (
	ErrTenantNotFound = errors.New("tenant not found")
)

// TenantService handles tenant business logic
type TenantService struct {
	tenantRepo *repository.TenantRepository
	db         *sql.DB
}

// NewTenantService creates a new tenant service
func NewTenantService(tenantRepo *repository.TenantRepository, db *sql.DB) *TenantService {
	return &TenantService{
		tenantRepo: tenantRepo,
		db:         db,
	}
}

// Create creates a new tenant
func (s *TenantService) Create(req domain.CreateTenantRequest) (*domain.Tenant, error) {
	// Check if subdomain already exists
	exists, err := s.tenantRepo.SubdomainExists(req.Subdomain)
	if err != nil {
		return nil, err
	}
	if exists {
		return nil, ErrSubdomainTaken
	}

	tenant := &domain.Tenant{
		Name:      req.Name,
		Domain:    req.Domain,
		Subdomain: req.Subdomain,
	}

	if err := s.tenantRepo.Create(tenant); err != nil {
		return nil, err
	}

	return tenant, nil
}

// GetByID retrieves a tenant by ID
func (s *TenantService) GetByID(id uuid.UUID) (*domain.Tenant, error) {
	tenant, err := s.tenantRepo.FindByID(id)
	if err != nil {
		return nil, err
	}
	if tenant == nil {
		return nil, ErrTenantNotFound
	}
	return tenant, nil
}

// GetBySubdomain retrieves a tenant by subdomain
func (s *TenantService) GetBySubdomain(subdomain string) (*domain.Tenant, error) {
	tenant, err := s.tenantRepo.FindBySubdomain(subdomain)
	if err != nil {
		return nil, err
	}
	if tenant == nil {
		return nil, ErrTenantNotFound
	}
	return tenant, nil
}

// ListAll retrieves all tenants
func (s *TenantService) ListAll() ([]*domain.Tenant, error) {
	return s.tenantRepo.FindAll()
}

// ListAllWithDetails retrieves all tenants with their plan and solutions information
func (s *TenantService) ListAllWithDetails() ([]map[string]interface{}, error) {
	tenants, err := s.tenantRepo.FindAll()
	if err != nil {
		return nil, err
	}

	var result []map[string]interface{}
	for _, tenant := range tenants {
		tenantData := map[string]interface{}{
			"id":                  tenant.ID,
			"name":                tenant.Name,
			"subdomain":           tenant.Subdomain,
			"domain":              tenant.Domain,
			"email":               tenant.Email,
			"phone":               tenant.Phone,
			"cnpj":                tenant.CNPJ,
			"is_active":           tenant.IsActive,
			"created_at":          tenant.CreatedAt,
			"logo_url":            tenant.LogoURL,
			"logo_horizontal_url": tenant.LogoHorizontalURL,
			"primary_color":       tenant.PrimaryColor,
			"secondary_color":     tenant.SecondaryColor,
		}

		// Buscar subscription e soluções
		var planName sql.NullString
		var planID string
		query := `
			SELECT 
				s.plan_id, 
				p.name as plan_name
			FROM agency_subscriptions s
			JOIN plans p ON s.plan_id = p.id
			WHERE s.agency_id = $1 AND s.status = 'active'
			LIMIT 1
		`
		err = s.db.QueryRow(query, tenant.ID).Scan(&planID, &planName)
		if err == nil && planName.Valid {
			tenantData["plan_name"] = planName.String

			// Buscar soluções do plano
			solutionsQuery := `
				SELECT sol.id, sol.name, sol.slug, sol.icon
				FROM solutions sol
				JOIN plan_solutions ps ON sol.id = ps.solution_id
				WHERE ps.plan_id = $1
				ORDER BY sol.name
			`
			rows, err := s.db.Query(solutionsQuery, planID)
			if err == nil {
				defer rows.Close()
				var solutions []map[string]interface{}
				for rows.Next() {
					var id, name, slug string
					var icon sql.NullString
					if err := rows.Scan(&id, &name, &slug, &icon); err == nil {
						solution := map[string]interface{}{
							"id":   id,
							"name": name,
							"slug": slug,
						}
						if icon.Valid {
							solution["icon"] = icon.String
						}
						solutions = append(solutions, solution)
					}
				}
				tenantData["solutions"] = solutions
			}
		}

		result = append(result, tenantData)
	}

	return result, nil
}

// Delete removes a tenant by ID
func (s *TenantService) Delete(id uuid.UUID) error {
	if err := s.tenantRepo.Delete(id); err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return ErrTenantNotFound
		}
		return err
	}
	return nil
}
