package repository

import (
	"context"
	"fmt"

	dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
	"github.com/jackc/pgx/v5/pgtype"
)

func convertCreateCompany(company domain.CreateCompany) dbgen.CreateCompanyParams {
	return dbgen.CreateCompanyParams{
		Name:     company.Name,
		AdminID:  company.AdminID,
		WalletID: company.WalletID,
	}
}

func convertDBCompany(dbCompany dbgen.Company) domain.Company {
	return domain.Company{
		ID:       dbCompany.ID,
		Name:     dbCompany.Name,
		AdminID:  dbCompany.AdminID,
		WalletID: dbCompany.WalletID,
	}
}

func convertDBCompanyDetails(dbCompany dbgen.CompaniesDetail) domain.GetCompany {
	return domain.GetCompany{
		ID:               dbCompany.ID,
		Name:             dbCompany.Name,
		AdminID:          dbCompany.AdminID,
		WalletID:         dbCompany.WalletID,
		WalletBalance:    domain.Currency(dbCompany.Balance),
		IsWalletActive:   dbCompany.IsActive,
		AdminFirstName:   dbCompany.AdminFirstName,
		AdminLastName:    dbCompany.AdminLastName,
		AdminPhoneNumber: dbCompany.AdminPhoneNumber.String,
	}
}

func convertUpdateCompany(updateCompany domain.UpdateCompany) dbgen.UpdateCompanyParams {
	var newUpdateCompany dbgen.UpdateCompanyParams

	newUpdateCompany.ID = updateCompany.ID

	if updateCompany.Name != nil {
		newUpdateCompany.Name = pgtype.Text{
			String: *updateCompany.Name,
			Valid:  true,
		}
	}

	if updateCompany.AdminID != nil {
		newUpdateCompany.AdminID = pgtype.Int8{
			Int64: *updateCompany.AdminID,
			Valid: true,
		}
	}

	return newUpdateCompany
}

func (s *Store) CreateCompany(ctx context.Context, company domain.CreateCompany) (domain.Company, error) {
	dbCompany, err := s.queries.CreateCompany(ctx, convertCreateCompany(company))
	if err != nil {
		return domain.Company{}, err
	}
	return convertDBCompany(dbCompany), nil
}

func (s *Store) GetAllCompanies(ctx context.Context) ([]domain.GetCompany, error) {
	dbCompanies, err := s.queries.GetAllCompanies(ctx)
	if err != nil {
		return nil, err
	}

	var companies []domain.GetCompany = make([]domain.GetCompany, 0, len(dbCompanies))
	for _, dbCompany := range dbCompanies {
		companies = append(companies, convertDBCompanyDetails(dbCompany))
	}

	return companies, nil
}

func (s *Store) SearchCompanyByName(ctx context.Context, name string) ([]domain.GetCompany, error) {
	dbCompanies, err := s.queries.SearchCompanyByName(ctx, pgtype.Text{
		String: name,
		Valid:  true,
	})

	if err != nil {
		return nil, err
	}
	var companies []domain.GetCompany = make([]domain.GetCompany, 0, len(dbCompanies))

	for _, dbCompany := range dbCompanies {
		companies = append(companies, convertDBCompanyDetails(dbCompany))
	}
	return companies, nil
}

func (s *Store) GetCompanyByID(ctx context.Context, id int64) (domain.GetCompany, error) {
	dbCompany, err := s.queries.GetCompanyByID(ctx, id)

	if err != nil {
		return domain.GetCompany{}, err
	}
	return convertDBCompanyDetails(dbCompany), nil
}

func (s *Store) UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error) {
	dbCompany, err := s.queries.UpdateCompany(ctx, convertUpdateCompany(company))

	if err != nil {
		return domain.Company{}, err
	}

	return convertDBCompany(dbCompany), nil
}

func (s *Store) DeleteCompany(ctx context.Context, id int64) error {
	return s.queries.DeleteCompany(ctx, id)
}

func (s *Store) GetCompanyCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error) {
	query := `SELECT 
        COUNT(*) as total,
        COUNT(CASE WHEN w.is_active = true THEN 1 END) as active,
        COUNT(CASE WHEN w.is_active = false THEN 1 END) as inactive
        FROM companies c
        JOIN wallets w ON c.wallet_id = w.id`

	args := []interface{}{}
	argPos := 1

	// Add filters if provided
	if filter.StartTime.Valid {
		query += fmt.Sprintf(" WHERE %screated_at >= $%d", func() string {
			if len(args) == 0 {
				return ""
			}
			return " AND "
		}(), argPos)
		args = append(args, filter.StartTime.Value)
		argPos++
	}
	if filter.EndTime.Valid {
		query += fmt.Sprintf(" AND created_at <= $%d", argPos)
		args = append(args, filter.EndTime.Value)
		argPos++
	}

	row := s.conn.QueryRow(ctx, query, args...)
	err = row.Scan(&total, &active, &inactive)
	if err != nil {
		return 0, 0, 0, fmt.Errorf("failed to get company counts: %w", err)
	}

	return total, active, inactive, nil
}
