package usecase

import (
	"context"
	"errors"
	"math"

	"github.com/gofrs/uuid/v5"

	"github.com/saveinmed/backend-go/internal/domain"
)

// RegisterCompany persists a new company and sets a new UUID.
func (s *Service) RegisterCompany(ctx context.Context, company *domain.Company) error {
	company.ID = uuid.Must(uuid.NewV7())
	return s.repo.CreateCompany(ctx, company)
}

// ListCompanies returns a paginated list of companies matching the filter.
func (s *Service) ListCompanies(ctx context.Context, filter domain.CompanyFilter, page, pageSize int) (*domain.CompanyPage, error) {
	if pageSize <= 0 {
		pageSize = 20
	}
	if page <= 0 {
		page = 1
	}
	filter.Limit = pageSize
	filter.Offset = (page - 1) * pageSize
	companies, total, err := s.repo.ListCompanies(ctx, filter)
	if err != nil {
		return nil, err
	}
	return &domain.CompanyPage{Companies: companies, Total: total, Page: page, PageSize: pageSize}, nil
}

// GetCompany retrieves a company by ID.
func (s *Service) GetCompany(ctx context.Context, id uuid.UUID) (*domain.Company, error) {
	return s.repo.GetCompany(ctx, id)
}

// UpdateCompany persists changes to an existing company.
func (s *Service) UpdateCompany(ctx context.Context, company *domain.Company) error {
	return s.repo.UpdateCompany(ctx, company)
}

// DeleteCompany removes a company by ID.
func (s *Service) DeleteCompany(ctx context.Context, id uuid.UUID) error {
	return s.repo.DeleteCompany(ctx, id)
}

// VerifyCompany marks the company account as KYC-verified.
func (s *Service) VerifyCompany(ctx context.Context, id uuid.UUID) (*domain.Company, error) {
	company, err := s.repo.GetCompany(ctx, id)
	if err != nil {
		return nil, err
	}
	company.IsVerified = true

	if err := s.repo.UpdateCompany(ctx, company); err != nil {
		return nil, err
	}
	return company, nil
}

// CalculateShippingOptions returns available delivery/pickup options for a vendor,
// based on the buyer's location and cart total.
func (s *Service) CalculateShippingOptions(ctx context.Context, vendorID uuid.UUID, buyerLat, buyerLng float64, cartTotalCents int64) ([]domain.ShippingOption, error) {
	company, err := s.repo.GetCompany(ctx, vendorID)
	if err != nil {
		return nil, err
	}
	if company == nil {
		return nil, errors.New("vendor not found")
	}

	settings, err := s.repo.GetShippingSettings(ctx, vendorID)
	if err != nil {
		return []domain.ShippingOption{}, nil
	}
	if settings == nil {
		return []domain.ShippingOption{}, nil
	}

	distance := domain.HaversineDistance(company.Latitude, company.Longitude, buyerLat, buyerLng)
	var options []domain.ShippingOption

	// Delivery option
	if settings.Active {
		if settings.MaxRadiusKm > 0 && distance <= settings.MaxRadiusKm {
			variableCost := int64(math.Round(distance * float64(settings.PricePerKmCents)))
			price := settings.MinFeeCents
			if variableCost > price {
				price = variableCost
			}
			if settings.FreeShippingThresholdCents != nil && *settings.FreeShippingThresholdCents > 0 && cartTotalCents >= *settings.FreeShippingThresholdCents {
				price = 0
			}

			estMins := 30 + int(math.Round(distance*5))

			options = append(options, domain.ShippingOption{
				Type:             domain.ShippingOptionTypeDelivery,
				ValueCents:       price,
				EstimatedMinutes: estMins,
				Description:      "Entrega Própria",
				DistanceKm:       distance,
			})
		}
	}

	// Pickup option
	if settings.PickupActive {
		desc := "Retirada na loja"
		if settings.PickupAddress != "" {
			desc = "Retirada em: " + settings.PickupAddress
		}
		if settings.PickupHours != "" {
			desc += " (" + settings.PickupHours + ")"
		}

		options = append(options, domain.ShippingOption{
			Type:             domain.ShippingOptionTypePickup,
			ValueCents:       0,
			EstimatedMinutes: 60,
			Description:      desc,
			DistanceKm:       distance,
		})
	}

	return options, nil
}
