package codigos

import (
	"context"
	"time"

	"photum-backend/internal/db/generated"

	"github.com/google/uuid"
	"github.com/jackc/pgx/v5/pgtype"
)

type Service struct {
	q *generated.Queries
}

func NewService(q *generated.Queries) *Service {
	return &Service{
		q: q,
	}
}

type CreateCodigoInput struct {
	Codigo       string `json:"codigo"`
	Descricao    string `json:"descricao"`
	ValidadeDias int32  `json:"validade_dias"`
	EmpresaID    string `json:"empresa_id"`
	Regiao       string `json:"regiao"` // From context/header
}

func (s *Service) Create(ctx context.Context, input CreateCodigoInput) (generated.CodigosAcesso, error) {
	days := input.ValidadeDias

	var expiraEm time.Time
	if days == -1 {
		// Infinite: 100 years
		expiraEm = time.Now().AddDate(100, 0, 0)
	} else {
		if days <= 0 {
			days = 30
		}
		expiraEm = time.Now().Add(time.Duration(days) * 24 * time.Hour)
	}

	var empresaUUID pgtype.UUID
	if input.EmpresaID != "" {
		parsed, err := uuid.Parse(input.EmpresaID)
		if err == nil {
			empresaUUID.Bytes = parsed
			empresaUUID.Valid = true
		}
	}

	// Default regiao to SP if empty
	regiao := input.Regiao
	if regiao == "" {
		regiao = "SP"
	}

	return s.q.CreateCodigoAcesso(ctx, generated.CreateCodigoAcessoParams{
		Codigo:       input.Codigo,
		Descricao:    pgtype.Text{String: input.Descricao, Valid: input.Descricao != ""},
		ValidadeDias: days,
		ExpiraEm:     pgtype.Timestamptz{Time: expiraEm, Valid: true},
		Ativo:        true,
		EmpresaID:    empresaUUID,
		Regiao:       pgtype.Text{String: regiao, Valid: true},
	})
}

func (s *Service) List(ctx context.Context, regiao string) ([]generated.ListCodigosAcessoRow, error) {
	if regiao == "" {
		regiao = "SP"
	}
	return s.q.ListCodigosAcesso(ctx, pgtype.Text{String: regiao, Valid: true})
}

func (s *Service) Delete(ctx context.Context, id string) error {
	uid, err := uuid.Parse(id)
	if err != nil {
		return err
	}

	// Convert uuid.UUID to pgtype.UUID
	var pgUUID pgtype.UUID
	pgUUID.Bytes = uid
	pgUUID.Valid = true

	return s.q.DeleteCodigoAcesso(ctx, pgUUID)
}

func (s *Service) GetByCode(ctx context.Context, code string) (generated.GetCodigoAcessoRow, error) {
	return s.q.GetCodigoAcesso(ctx, code)
}

func (s *Service) IncrementUse(ctx context.Context, id uuid.UUID) error {
	var pgUUID pgtype.UUID
	pgUUID.Bytes = id
	pgUUID.Valid = true
	return s.q.IncrementCodigoAcessoUso(ctx, pgUUID)
}

// Custom error for validation
type AppError struct {
	Message string
}

func (e *AppError) Error() string {
	return e.Message
}

func (s *Service) Verify(ctx context.Context, code string) (*generated.GetCodigoAcessoRow, error) {
	c, err := s.q.GetCodigoAcesso(ctx, code)
	if err != nil {
		return nil, err // Not found or DB error
	}

	if !c.Ativo {
		return nil, &AppError{Message: "Código inativo"}
	}

	if time.Now().After(c.ExpiraEm.Time) {
		return nil, &AppError{Message: "Código expirado"}
	}

	return &c, nil
}
