package repository

import (
	"database/sql"
	"time"

	"aggios-app/backend/internal/domain"

	"github.com/google/uuid"
)

// TenantRepository handles database operations for tenants
type TenantRepository struct {
	db *sql.DB
}

// NewTenantRepository creates a new tenant repository
func NewTenantRepository(db *sql.DB) *TenantRepository {
	return &TenantRepository{db: db}
}

// DB returns the underlying database connection
func (r *TenantRepository) DB() *sql.DB {
	return r.db
}

// Create creates a new tenant
func (r *TenantRepository) Create(tenant *domain.Tenant) error {
	query := `
		INSERT INTO tenants (
			id, name, domain, subdomain, cnpj, razao_social, email, phone, website,
			address, neighborhood, number, complement, city, state, zip,
			description, industry, team_size, primary_color, secondary_color,
			logo_url, logo_horizontal_url, created_at, updated_at
		)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25)
		RETURNING id, created_at, updated_at
	`

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

	return r.db.QueryRow(
		query,
		tenant.ID,
		tenant.Name,
		tenant.Domain,
		tenant.Subdomain,
		tenant.CNPJ,
		tenant.RazaoSocial,
		tenant.Email,
		tenant.Phone,
		tenant.Website,
		tenant.Address,
		tenant.Neighborhood,
		tenant.Number,
		tenant.Complement,
		tenant.City,
		tenant.State,
		tenant.Zip,
		tenant.Description,
		tenant.Industry,
		tenant.TeamSize,
		tenant.PrimaryColor,
		tenant.SecondaryColor,
		tenant.LogoURL,
		tenant.LogoHorizontalURL,
		tenant.CreatedAt,
		tenant.UpdatedAt,
	).Scan(&tenant.ID, &tenant.CreatedAt, &tenant.UpdatedAt)
}

// FindByID finds a tenant by ID
func (r *TenantRepository) FindByID(id uuid.UUID) (*domain.Tenant, error) {
	query := `
		SELECT id, name, domain, subdomain, cnpj, razao_social, email, phone, website,
		       address, neighborhood, number, complement, city, state, zip, description, industry, team_size,
		       primary_color, secondary_color, logo_url, logo_horizontal_url,
		       is_active, created_at, updated_at
		FROM tenants
		WHERE id = $1
	`

	tenant := &domain.Tenant{}
		var cnpj, razaoSocial, email, phone, website, address, neighborhood, number, complement, city, state, zip, description, industry, teamSize, primaryColor, secondaryColor, logoURL, logoHorizontalURL sql.NullString

	err := r.db.QueryRow(query, id).Scan(
		&tenant.ID,
		&tenant.Name,
		&tenant.Domain,
		&tenant.Subdomain,
		&cnpj,
		&razaoSocial,
		&email,
		&phone,
		&website,
		&address,
		&neighborhood,
		&number,
		&complement,
		&city,
		&state,
		&zip,
		&description,
		&industry,
		&teamSize,
		&primaryColor,
		&secondaryColor,
		&logoURL,
		&logoHorizontalURL,
		&tenant.IsActive,
		&tenant.CreatedAt,
		&tenant.UpdatedAt,
	)

	if err == sql.ErrNoRows {
		return nil, nil
	}

	if err != nil {
		return nil, err
	}

	// Handle nullable fields
	if cnpj.Valid {
		tenant.CNPJ = cnpj.String
	}
	if razaoSocial.Valid {
		tenant.RazaoSocial = razaoSocial.String
	}
	if email.Valid {
		tenant.Email = email.String
	}
	if phone.Valid {
		tenant.Phone = phone.String
	}
	if website.Valid {
		tenant.Website = website.String
	}
	if address.Valid {
		tenant.Address = address.String
	}
	if neighborhood.Valid {
		tenant.Neighborhood = neighborhood.String
	}
	if number.Valid {
		tenant.Number = number.String
	}
	if complement.Valid {
		tenant.Complement = complement.String
	}
	if city.Valid {
		tenant.City = city.String
	}
	if state.Valid {
		tenant.State = state.String
	}
	if zip.Valid {
		tenant.Zip = zip.String
	}
	if description.Valid {
		tenant.Description = description.String
	}
	if industry.Valid {
		tenant.Industry = industry.String
	}
	if teamSize.Valid {
		tenant.TeamSize = teamSize.String
	}
	if primaryColor.Valid {
		tenant.PrimaryColor = primaryColor.String
	}
	if secondaryColor.Valid {
		tenant.SecondaryColor = secondaryColor.String
	}
	if logoURL.Valid {
		tenant.LogoURL = logoURL.String
	}
	if logoHorizontalURL.Valid {
		tenant.LogoHorizontalURL = logoHorizontalURL.String
	}

	return tenant, nil
}

// FindBySubdomain finds a tenant by subdomain
func (r *TenantRepository) FindBySubdomain(subdomain string) (*domain.Tenant, error) {
	query := `
		SELECT id, name, domain, subdomain, primary_color, secondary_color, logo_url, logo_horizontal_url, created_at, updated_at
		FROM tenants
		WHERE subdomain = $1
	`

	tenant := &domain.Tenant{}
	var primaryColor, secondaryColor, logoURL, logoHorizontalURL sql.NullString

	err := r.db.QueryRow(query, subdomain).Scan(
		&tenant.ID,
		&tenant.Name,
		&tenant.Domain,
		&tenant.Subdomain,
		&primaryColor,
		&secondaryColor,
		&logoURL,
		&logoHorizontalURL,
		&tenant.CreatedAt,
		&tenant.UpdatedAt,
	)

	if err == sql.ErrNoRows {
		return nil, nil
	}

	if err != nil {
		return nil, err
	}

	if primaryColor.Valid {
		tenant.PrimaryColor = primaryColor.String
	}
	if secondaryColor.Valid {
		tenant.SecondaryColor = secondaryColor.String
	}
	if logoURL.Valid {
		tenant.LogoURL = logoURL.String
	}
	if logoHorizontalURL.Valid {
		tenant.LogoHorizontalURL = logoHorizontalURL.String
	}

	return tenant, nil
}

// SubdomainExists checks if a subdomain is already taken
func (r *TenantRepository) SubdomainExists(subdomain string) (bool, error) {
	var exists bool
	query := `SELECT EXISTS(SELECT 1 FROM tenants WHERE subdomain = $1)`
	err := r.db.QueryRow(query, subdomain).Scan(&exists)
	return exists, err
}

// FindAll returns all tenants
func (r *TenantRepository) FindAll() ([]*domain.Tenant, error) {
	query := `
		SELECT id, name, domain, subdomain, email, phone, cnpj, logo_url, is_active, created_at, updated_at
		FROM tenants
		ORDER BY created_at DESC
	`

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

	var tenants []*domain.Tenant
	for rows.Next() {
		tenant := &domain.Tenant{}
		var email, phone, cnpj, logoURL sql.NullString

		err := rows.Scan(
			&tenant.ID,
			&tenant.Name,
			&tenant.Domain,
			&tenant.Subdomain,
			&email,
			&phone,
			&cnpj,
			&logoURL,
			&tenant.IsActive,
			&tenant.CreatedAt,
			&tenant.UpdatedAt,
		)
		if err != nil {
			return nil, err
		}

		if email.Valid {
			tenant.Email = email.String
		}
		if phone.Valid {
			tenant.Phone = phone.String
		}
		if cnpj.Valid {
			tenant.CNPJ = cnpj.String
		}
		if logoURL.Valid {
			tenant.LogoURL = logoURL.String
		}

		tenants = append(tenants, tenant)
	}

	if tenants == nil {
		return []*domain.Tenant{}, nil
	}

	return tenants, nil
}

// Delete removes a tenant (and cascades to related data)
func (r *TenantRepository) Delete(id uuid.UUID) error {
	// Start transaction
	tx, err := r.db.Begin()
	if err != nil {
		return err
	}
	defer tx.Rollback()

	// Delete all users associated with this tenant first
	_, err = tx.Exec(`DELETE FROM users WHERE tenant_id = $1`, id)
	if err != nil {
		return err
	}

	// Delete the tenant
	result, err := tx.Exec(`DELETE FROM tenants WHERE id = $1`, id)
	if err != nil {
		return err
	}

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

	if rows == 0 {
		return sql.ErrNoRows
	}

	// Commit transaction
	return tx.Commit()
}

// UpdateProfile updates tenant profile information
func (r *TenantRepository) UpdateProfile(id uuid.UUID, updates map[string]interface{}) error {
	query := `
		UPDATE tenants SET
			name = COALESCE($1, name),
			cnpj = COALESCE($2, cnpj),
			razao_social = COALESCE($3, razao_social),
			email = COALESCE($4, email),
			phone = COALESCE($5, phone),
			website = COALESCE($6, website),
			address = COALESCE($7, address),
			neighborhood = COALESCE($8, neighborhood),
			number = COALESCE($9, number),
			complement = COALESCE($10, complement),
			city = COALESCE($11, city),
			state = COALESCE($12, state),
			zip = COALESCE($13, zip),
			description = COALESCE($14, description),
			industry = COALESCE($15, industry),
			team_size = COALESCE($16, team_size),
			primary_color = COALESCE($17, primary_color),
			secondary_color = COALESCE($18, secondary_color),
			logo_url = COALESCE($19, logo_url),
			logo_horizontal_url = COALESCE($20, logo_horizontal_url),
			updated_at = $21
		WHERE id = $22
	`

	_, err := r.db.Exec(
		query,
		updates["name"],
		updates["cnpj"],
		updates["razao_social"],
		updates["email"],
		updates["phone"],
		updates["website"],
		updates["address"],
		updates["neighborhood"],
		updates["number"],
		updates["complement"],
		updates["city"],
		updates["state"],
		updates["zip"],
		updates["description"],
		updates["industry"],
		updates["team_size"],
		updates["primary_color"],
		updates["secondary_color"],
		updates["logo_url"],
		updates["logo_horizontal_url"],
		time.Now(),
		id,
	)

	return err
}

// UpdateStatus updates the is_active status of a tenant
func (r *TenantRepository) UpdateStatus(id uuid.UUID, isActive bool) error {
	query := `UPDATE tenants SET is_active = $1, updated_at = $2 WHERE id = $3`
	_, err := r.db.Exec(query, isActive, time.Now(), id)
	return err
}
