package agenda

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"sort"
	"strconv"
	"strings"
	"time"

	"photum-backend/internal/config"
	"photum-backend/internal/db/generated"
	"photum-backend/internal/notification"

	"photum-backend/internal/finance"

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

type Service struct {
	queries        *generated.Queries
	notification   *notification.Service
	financeService *finance.Service
	cfg            *config.Config
}

func NewService(db *generated.Queries, notif *notification.Service, cfg *config.Config, fin *finance.Service) *Service {
	return &Service{
		queries:        db,
		notification:   notif,
		cfg:            cfg,
		financeService: fin,
	}
}

type ContactInfo struct {
	Name  string `json:"name"`
	Role  string `json:"role"`
	Phone string `json:"phone"`
}

type CreateAgendaRequest struct {
	FotID                uuid.UUID     `json:"fot_id"`
	DataEvento           time.Time     `json:"data_evento"`
	TipoEventoID         uuid.UUID     `json:"tipo_evento_id"`
	ObservacoesEvento    string        `json:"observacoes_evento"`
	LocalEvento          string        `json:"local_evento"`
	Endereco             string        `json:"endereco"`
	Horario              string        `json:"horario"`
	QtdFormandos         int32         `json:"qtd_formandos"`
	QtdFotografos        int32         `json:"qtd_fotografos"`
	QtdRecepcionistas    int32         `json:"qtd_recepcionistas"`
	QtdCinegrafistas     int32         `json:"qtd_cinegrafistas"`
	QtdEstudios          int32         `json:"qtd_estudios"`
	QtdPontoFoto         int32         `json:"qtd_ponto_foto"`
	QtdPontoID           int32         `json:"qtd_ponto_id"`
	QtdPontoDecorado     int32         `json:"qtd_ponto_decorado"`
	QtdPontosLed         int32         `json:"qtd_pontos_led"`
	QtdPlataforma360     int32         `json:"qtd_plataforma_360"`
	StatusProfissionais  string        `json:"status_profissionais"`
	FotoFaltante         int32         `json:"foto_faltante"`
	RecepFaltante        int32         `json:"recep_faltante"`
	CineFaltante         int32         `json:"cine_faltante"`
	LogisticaObservacoes string        `json:"logistica_observacoes"`
	PreVenda             bool          `json:"pre_venda"`
	Contatos             []ContactInfo `json:"contatos"`
}

type Assignment struct {
	ProfessionalID string  `json:"professional_id"`
	Status         string  `json:"status"`
	MotivoRejeicao *string `json:"motivo_rejeicao"`
	FuncaoID       *string `json:"funcao_id"`
	IsCoordinator  bool    `json:"is_coordinator"`
}

type AgendaResponse struct {
	generated.ListAgendasRow
	ParsedAssignments   []Assignment  `json:"assignments"`
	ParsedContacts      []ContactInfo `json:"contacts"`
	ShadowFotFinalizada bool          `json:"fot_finalizada"`
	ShadowFotPreVenda   bool          `json:"fot_pre_venda"`
}

func (s *Service) CalculateStatus(fotoFaltante, recepFaltante, cineFaltante int32) string {
	if fotoFaltante < 0 || recepFaltante < 0 || cineFaltante < 0 {
		return "ERRO"
	}

	sum := fotoFaltante + recepFaltante + cineFaltante
	if sum == 0 {
		return "OK"
	} else if sum > 0 {
		return "FALTA"
	}

	return "ERRO"
}

func (s *Service) Create(ctx context.Context, userID uuid.UUID, req CreateAgendaRequest, regiao string) (generated.Agenda, error) {
	status := s.CalculateStatus(req.FotoFaltante, req.RecepFaltante, req.CineFaltante)

	contatosBytes, _ := json.Marshal(req.Contatos)

	// Check if FOT is finalized
	fot, err := s.queries.GetCadastroFotByID(ctx, generated.GetCadastroFotByIDParams{
		ID:     pgtype.UUID{Bytes: req.FotID, Valid: true},
		Regiao: pgtype.Text{String: regiao, Valid: true},
	})
	if err != nil {
		return generated.Agenda{}, fmt.Errorf("erro ao buscar FOT: %v", err)
	}
	if fot.Finalizada.Bool {
		return generated.Agenda{}, fmt.Errorf("esta turma foi finalizada e não aceita novos eventos")
	}

	params := generated.CreateAgendaParams{
		FotID:                pgtype.UUID{Bytes: req.FotID, Valid: true},
		DataEvento:           pgtype.Date{Time: req.DataEvento, Valid: true},
		TipoEventoID:         pgtype.UUID{Bytes: req.TipoEventoID, Valid: true},
		ObservacoesEvento:    pgtype.Text{String: req.ObservacoesEvento, Valid: req.ObservacoesEvento != ""},
		LocalEvento:          pgtype.Text{String: req.LocalEvento, Valid: req.LocalEvento != ""},
		Endereco:             pgtype.Text{String: req.Endereco, Valid: req.Endereco != ""},
		Horario:              pgtype.Text{String: req.Horario, Valid: req.Horario != ""},
		QtdFormandos:         pgtype.Int4{Int32: req.QtdFormandos, Valid: true},
		QtdFotografos:        pgtype.Int4{Int32: req.QtdFotografos, Valid: true},
		QtdRecepcionistas:    pgtype.Int4{Int32: req.QtdRecepcionistas, Valid: true},
		QtdCinegrafistas:     pgtype.Int4{Int32: req.QtdCinegrafistas, Valid: true},
		QtdEstudios:          pgtype.Int4{Int32: req.QtdEstudios, Valid: true},
		QtdPontoFoto:         pgtype.Int4{Int32: req.QtdPontoFoto, Valid: true},
		QtdPontoID:           pgtype.Int4{Int32: req.QtdPontoID, Valid: true},
		QtdPontoDecorado:     pgtype.Int4{Int32: req.QtdPontoDecorado, Valid: true},
		QtdPontosLed:         pgtype.Int4{Int32: req.QtdPontosLed, Valid: true},
		QtdPlataforma360:     pgtype.Int4{Int32: req.QtdPlataforma360, Valid: true},
		StatusProfissionais:  pgtype.Text{String: status, Valid: true},
		FotoFaltante:         pgtype.Int4{Int32: req.FotoFaltante, Valid: true},
		RecepFaltante:        pgtype.Int4{Int32: req.RecepFaltante, Valid: true},
		CineFaltante:         pgtype.Int4{Int32: req.CineFaltante, Valid: true},
		LogisticaObservacoes: pgtype.Text{String: req.LogisticaObservacoes, Valid: req.LogisticaObservacoes != ""},
		PreVenda:             pgtype.Bool{Bool: req.PreVenda, Valid: true},
		UserID:               pgtype.UUID{Bytes: userID, Valid: true},
		Regiao:               pgtype.Text{String: regiao, Valid: true},
		Contatos:             contatosBytes,
	}

	return s.queries.CreateAgenda(ctx, params)
}

func (s *Service) List(ctx context.Context, userID uuid.UUID, role string, regiao string) ([]AgendaResponse, error) {
	var rows []generated.ListAgendasRow
	var err error

	// If role is CLIENT (cliente) or EVENT_OWNER
	if role == "cliente" || role == "EVENT_OWNER" {
		// New Logic: Fetch User's Company
		user, err := s.queries.GetUsuarioByID(ctx, pgtype.UUID{Bytes: userID, Valid: true})
		if err != nil {
			return nil, fmt.Errorf("erro ao buscar usuário para filtro de empresa: %v", err)
		}

		if !user.EmpresaID.Valid {
			// If no company linked, return empty or error? Empty seems safer.
			return []AgendaResponse{}, nil
		}

		listRows, err := s.queries.ListAgendasByCompany(ctx, generated.ListAgendasByCompanyParams{
			EmpresaID: user.EmpresaID,
			Regiao:    pgtype.Text{String: regiao, Valid: true},
		})
		if err != nil {
			return nil, err
		}
		// Convert ListAgendasByCompanyRow to ListAgendasRow manually
		for _, r := range listRows {
			rows = append(rows, generated.ListAgendasRow{
				ID:                    r.ID,
				UserID:                r.UserID,
				FotID:                 r.FotID,
				DataEvento:            r.DataEvento,
				TipoEventoID:          r.TipoEventoID,
				ObservacoesEvento:     r.ObservacoesEvento,
				LocalEvento:           r.LocalEvento,
				Endereco:              r.Endereco,
				Horario:               r.Horario,
				QtdFormandos:          r.QtdFormandos,
				QtdFotografos:         r.QtdFotografos,
				QtdRecepcionistas:     r.QtdRecepcionistas,
				QtdCinegrafistas:      r.QtdCinegrafistas,
				QtdEstudios:           r.QtdEstudios,
				QtdPontoFoto:          r.QtdPontoFoto,
				QtdPontoID:            r.QtdPontoID,
				QtdPontoDecorado:      r.QtdPontoDecorado,
				QtdPontosLed:          r.QtdPontosLed,
				QtdPlataforma360:      r.QtdPlataforma360,
				StatusProfissionais:   r.StatusProfissionais,
				FotoFaltante:          r.FotoFaltante,
				RecepFaltante:         r.RecepFaltante,
				CineFaltante:          r.CineFaltante,
				LogisticaObservacoes:  r.LogisticaObservacoes,
				PreVenda:              r.PreVenda,
				CriadoEm:              r.CriadoEm,
				AtualizadoEm:          r.AtualizadoEm,
				Status:                r.Status,
				FotNumero:             r.FotNumero,
				Instituicao:           r.Instituicao,
				CursoNome:             r.CursoNome,
				EmpresaNome:           r.EmpresaNome,
				EmpresaID:             r.EmpresaID,
				FotFinalizada:         r.FotFinalizada,
				FotPreVenda:           r.FotPreVenda,
				AnoSemestre:           r.AnoSemestre,
				ObservacoesFot:        r.ObservacoesFot,
				TipoEventoNome:        r.TipoEventoNome,
				AssignedProfessionals: r.AssignedProfessionals,
				Contatos:              r.Contatos,
			})
		}
	} else {
		rows, err = s.queries.ListAgendas(ctx, pgtype.Text{String: regiao, Valid: true})
		if err != nil {
			return nil, err
		}
		// DEBUG: Check first few rows
		for i, r := range rows {
			if i < 5 {
				fmt.Printf("DEBUG SERVICE ADMIN PATH: Row %d ID=%s FotFinalizada=%v FotPreVenda=%v\n", i, r.ID.Bytes, r.FotFinalizada.Bool, r.FotPreVenda.Bool)
			}
		}
	}

	var response []AgendaResponse
	for _, row := range rows {
		var assignments []Assignment
		if row.AssignedProfessionals != nil {
			bytes, ok := row.AssignedProfessionals.([]byte)
			if !ok {
				str, ok := row.AssignedProfessionals.(string)
				if ok {
					bytes = []byte(str)
				}
			}
			if bytes != nil {
				json.Unmarshal(bytes, &assignments)
			}
		}

		var contacts []ContactInfo
		if len(row.Contatos) > 0 {
			json.Unmarshal(row.Contatos, &contacts)
		}

		response = append(response, AgendaResponse{
			ListAgendasRow:      row,
			ParsedAssignments:   assignments,
			ParsedContacts:      contacts,
			ShadowFotFinalizada: row.FotFinalizada.Bool,
			ShadowFotPreVenda:   row.FotPreVenda.Bool,
		})
	}

	return response, nil
}

func (s *Service) Get(ctx context.Context, id uuid.UUID, regiao string) (generated.Agenda, error) {
	return s.queries.GetAgenda(ctx, generated.GetAgendaParams{
		ID:     pgtype.UUID{Bytes: id, Valid: true},
		Regiao: pgtype.Text{String: regiao, Valid: true},
	})
}

func (s *Service) Update(ctx context.Context, id uuid.UUID, req CreateAgendaRequest, regiao string) (generated.Agenda, error) {
	if req.FotID == uuid.Nil {
		return generated.Agenda{}, fmt.Errorf("FOT ID inválido ou não informado")
	}
	if req.TipoEventoID == uuid.Nil {
		return generated.Agenda{}, fmt.Errorf("Tipo de Evento ID inválido ou não informado")
	}

	// Check if FOT is finalized
	fot, err := s.queries.GetCadastroFotByID(ctx, generated.GetCadastroFotByIDParams{
		ID:     pgtype.UUID{Bytes: req.FotID, Valid: true},
		Regiao: pgtype.Text{String: regiao, Valid: true},
	})
	if err != nil {
		return generated.Agenda{}, fmt.Errorf("erro ao buscar FOT: %v", err)
	}
	if fot.Finalizada.Bool {
		return generated.Agenda{}, fmt.Errorf("esta turma foi finalizada e não aceita edições neste evento")
	}

	status := s.CalculateStatus(req.FotoFaltante, req.RecepFaltante, req.CineFaltante)

	contatosBytes, _ := json.Marshal(req.Contatos)

	params := generated.UpdateAgendaParams{
		ID:                   pgtype.UUID{Bytes: id, Valid: true},
		FotID:                pgtype.UUID{Bytes: req.FotID, Valid: true},
		DataEvento:           pgtype.Date{Time: req.DataEvento, Valid: true},
		TipoEventoID:         pgtype.UUID{Bytes: req.TipoEventoID, Valid: true},
		ObservacoesEvento:    pgtype.Text{String: req.ObservacoesEvento, Valid: req.ObservacoesEvento != ""},
		LocalEvento:          pgtype.Text{String: req.LocalEvento, Valid: req.LocalEvento != ""},
		Endereco:             pgtype.Text{String: req.Endereco, Valid: req.Endereco != ""},
		Horario:              pgtype.Text{String: req.Horario, Valid: req.Horario != ""},
		QtdFormandos:         pgtype.Int4{Int32: req.QtdFormandos, Valid: true},
		QtdFotografos:        pgtype.Int4{Int32: req.QtdFotografos, Valid: true},
		QtdRecepcionistas:    pgtype.Int4{Int32: req.QtdRecepcionistas, Valid: true},
		QtdCinegrafistas:     pgtype.Int4{Int32: req.QtdCinegrafistas, Valid: true},
		QtdEstudios:          pgtype.Int4{Int32: req.QtdEstudios, Valid: true},
		QtdPontoFoto:         pgtype.Int4{Int32: req.QtdPontoFoto, Valid: true},
		QtdPontoID:           pgtype.Int4{Int32: req.QtdPontoID, Valid: true},
		QtdPontoDecorado:     pgtype.Int4{Int32: req.QtdPontoDecorado, Valid: true},
		QtdPontosLed:         pgtype.Int4{Int32: req.QtdPontosLed, Valid: true},
		QtdPlataforma360:     pgtype.Int4{Int32: req.QtdPlataforma360, Valid: true},
		StatusProfissionais:  pgtype.Text{String: status, Valid: true},
		FotoFaltante:         pgtype.Int4{Int32: req.FotoFaltante, Valid: true},
		RecepFaltante:        pgtype.Int4{Int32: req.RecepFaltante, Valid: true},
		CineFaltante:         pgtype.Int4{Int32: req.CineFaltante, Valid: true},
		LogisticaObservacoes: pgtype.Text{String: req.LogisticaObservacoes, Valid: req.LogisticaObservacoes != ""},
		PreVenda:             pgtype.Bool{Bool: req.PreVenda, Valid: true},
		Regiao:               pgtype.Text{String: regiao, Valid: true},
		Contatos:             contatosBytes,
	}
	return s.queries.UpdateAgenda(ctx, params)
}

func (s *Service) Delete(ctx context.Context, id uuid.UUID, regiao string) error {
	return s.queries.DeleteAgenda(ctx, generated.DeleteAgendaParams{
		ID:     pgtype.UUID{Bytes: id, Valid: true},
		Regiao: pgtype.Text{String: regiao, Valid: true},
	})
}

func (s *Service) AssignProfessional(ctx context.Context, agendaID uuid.UUID, profID uuid.UUID, funcaoID *uuid.UUID, regiao string) error {
	params := generated.AssignProfessionalParams{
		AgendaID:       pgtype.UUID{Bytes: agendaID, Valid: true},
		ProfissionalID: pgtype.UUID{Bytes: profID, Valid: true},
	}

	if funcaoID != nil {
		params.FuncaoID = pgtype.UUID{Bytes: *funcaoID, Valid: true}
	} else {
		params.FuncaoID = pgtype.UUID{Valid: false}
	}

	if err := s.queries.AssignProfessional(ctx, params); err != nil {
		return err
	}

	// Notification Logic (Async or Sync - staying Sync but safe for now)
	go func() {
		// Create a detached context for the notification to avoid cancellation if the HTTP request ends
		// Note: Ideally use a proper background context with timeout
		bgCtx := context.Background()

		// 1. Get Agenda Details
		// 1. Get Agenda Details. To notify successfully we need region?
		// Since this is async/background, we might not have region context easily if we don't pass it.
		// GetAgenda now requires regiao.
		// We passed agendaID.
		// We should probably rely on a GetAgendaByIDOnly query for system tasks?
		// Or pass region to AssignProfessional and then to NotifyLogistics.
		// For now, let's assume 'SP' default if background, OR we need access to the region.
		// Wait, we don't have region here.
		// Notification logic is tricky with strict isolation.
		// But Wait, I can't call GetAgenda without Regiao now.
		// I must fix Notify to accept Regiao, or use a system query.
		// I'll skip fixing Notify call sites for a moment and focus on signatures.
		// Actually, I should probably pass Regiao to AssignProfessional too.
		// But AssignProfessional only modifies junction table.
		// The Notification part reads Agenda.
		// I'll add Regiao to AssignProfessional signature.
		agenda, err := s.queries.GetAgenda(bgCtx, generated.GetAgendaParams{
			ID:     pgtype.UUID{Bytes: agendaID, Valid: true},
			Regiao: pgtype.Text{String: regiao, Valid: true},
		})
		if err != nil {
			log.Printf("[Notification] Erro ao buscar dados da agenda para notificação: %v", err)
			return
		}

		// 2. Get Professional Details
		// We use GetProfissionalByID which returns the struct we need
		prof, err := s.queries.GetProfissionalByID(bgCtx, generated.GetProfissionalByIDParams{
			ID:     pgtype.UUID{Bytes: profID, Valid: true},
			Regiao: pgtype.Text{String: regiao, Valid: true},
		})
		if err != nil {
			log.Printf("[Notification] Erro ao buscar dados do profissional para notificação: %v", err)
			return
		}

		if prof.Whatsapp.String == "" {
			log.Printf("[Notification] Profissional %s sem WhatsApp cadastrado. Ignorando.", prof.Nome)
			return
		}

		// 3. Get Event Type Details to show the name
		// We need to fetch the TipoEvento name
		var tipoEventoNome string = "Evento"
		if agenda.TipoEventoID.Valid {
			tipoEvento, err := s.queries.GetTipoEventoByID(bgCtx, generated.GetTipoEventoByIDParams{
				ID:     pgtype.UUID{Bytes: agenda.TipoEventoID.Bytes, Valid: true},
				Regiao: pgtype.Text{String: regiao, Valid: true},
			})
			if err == nil {
				tipoEventoNome = tipoEvento.Nome
			} else {
				log.Printf("[Notification] Erro ao buscar tipo de evento: %v", err)
			}
		}

		// 4. Format Message
		dataEvento := "Data a definir"
		if agenda.DataEvento.Valid {
			dataEvento = agenda.DataEvento.Time.Format("02/01/2006")
		}

		horario := "Horário a definir"
		if agenda.Horario.Valid && agenda.Horario.String != "" {
			horario = agenda.Horario.String
		}

		local := "Local a definir"
		if agenda.LocalEvento.Valid && agenda.LocalEvento.String != "" {
			local = agenda.LocalEvento.String
		}

		if agenda.Endereco.Valid && agenda.Endereco.String != "" {
			local += fmt.Sprintf(" (%s)", agenda.Endereco.String)
		}

		// Use configured FRONTEND_URL or default to localhost
		baseUrl := "http://localhost:3000"
		if s.cfg != nil && s.cfg.FrontendURL != "" {
			baseUrl = s.cfg.FrontendURL
		}

		// Refined Message:
		msg := fmt.Sprintf("Olá *%s*! 📸\n\nVocê foi escalado(a) para um evento no dia *%s*.\n\n*Tipo:* %s\n*Horário:* %s\n*Local:* %s\n\nAcesse seu painel na Photum para conferir os detalhes e confirmar sua presença.\n%s/entrar",
			prof.Nome,
			dataEvento,
			tipoEventoNome,
			horario,
			local,
			baseUrl,
		)

		if err := s.notification.SendWhatsApp(prof.Whatsapp.String, msg); err != nil {
			log.Printf("[Notification] Falha ao enviar WhatsApp para %s: %v", prof.Nome, err)
		}
	}()

	return nil
}

func (s *Service) SetCoordinator(ctx context.Context, agendaID, profID uuid.UUID, isCoordinator bool) error {
	return s.queries.SetCoordinator(ctx, generated.SetCoordinatorParams{
		AgendaID:       pgtype.UUID{Bytes: agendaID, Valid: true},
		ProfissionalID: pgtype.UUID{Bytes: profID, Valid: true},
		IsCoordinator:  pgtype.Bool{Bool: isCoordinator, Valid: true},
	})
}

func (s *Service) RemoveProfessional(ctx context.Context, agendaID uuid.UUID, profID uuid.UUID) error {
	params := generated.RemoveProfessionalParams{
		AgendaID:       pgtype.UUID{Bytes: agendaID, Valid: true},
		ProfissionalID: pgtype.UUID{Bytes: profID, Valid: true},
	}
	return s.queries.RemoveProfessional(ctx, params)
}

func (s *Service) GetAgendaProfessionals(ctx context.Context, agendaID uuid.UUID) ([]generated.GetAgendaProfessionalsRow, error) {
	return s.queries.GetAgendaProfessionals(ctx, pgtype.UUID{Bytes: agendaID, Valid: true})
}

func (s *Service) UpdateStatus(ctx context.Context, agendaID uuid.UUID, status string, regiao string) (generated.Agenda, error) {
	params := generated.UpdateAgendaStatusParams{
		ID:     pgtype.UUID{Bytes: agendaID, Valid: true},
		Status: pgtype.Text{String: status, Valid: true},
		Regiao: pgtype.Text{String: regiao, Valid: true}, // Added via SQL modification
	}

	agenda, err := s.queries.UpdateAgendaStatus(ctx, params)
	if err != nil {
		return generated.Agenda{}, err
	}

	// Se o evento for confirmado, enviar notificações com logística
	// [MODIFIED] User requested to NOT send notification on approval. Only manually via logistics panel.
	// if status == "Confirmado" {
	// 	go s.NotifyLogistics(context.Background(), agendaID, nil, regiao)
	// }

	return agenda, nil
}

func (s *Service) NotifyLogistics(ctx context.Context, agendaID uuid.UUID, passengerOrders map[string]map[string]int, regiao string) error {
	// 1. Buscar Detalhes do Evento
	bgCtx := context.Background() // Isolate context for background execution if needed, but if valid ctx passed use it?
	// If caller passed context.Background(), fine.
	agenda, err := s.queries.GetAgenda(ctx, generated.GetAgendaParams{
		ID:     pgtype.UUID{Bytes: agendaID, Valid: true},
		Regiao: pgtype.Text{String: regiao, Valid: true},
	})
	if err != nil {
		log.Printf("[Notification] Erro ao buscar agenda: %v", err)
		return err
	}

	tipoEventoNome := "Evento"
	if agenda.TipoEventoID.Valid {
		te, err := s.queries.GetTipoEventoByID(bgCtx, generated.GetTipoEventoByIDParams{
			ID:     pgtype.UUID{Bytes: agenda.TipoEventoID.Bytes, Valid: true},
			Regiao: pgtype.Text{String: regiao, Valid: true},
		})
		if err == nil {
			tipoEventoNome = te.Nome
		}
	}

	dataFmt := "Data a definir"
	if agenda.DataEvento.Valid {
		dataFmt = agenda.DataEvento.Time.Format("02/01/2006")
	}
	horaFmt := "Horário a definir"
	if agenda.Horario.Valid {
		horaFmt = agenda.Horario.String
	}
	localFmt := ""
	if agenda.LocalEvento.Valid && agenda.LocalEvento.String != "" {
		localFmt = agenda.LocalEvento.String
	}
	if agenda.Endereco.Valid && agenda.Endereco.String != "" {
		if localFmt != "" {
			localFmt += " - " + agenda.Endereco.String
		} else {
			localFmt = agenda.Endereco.String
		}
	}
	if localFmt == "" {
		localFmt = "Local a definir"
	}

	// 2. Buscar Profissionais Escalados
	profs, err := s.queries.GetAgendaProfessionals(bgCtx, pgtype.UUID{Bytes: agendaID, Valid: true})
	if err != nil {
		log.Printf("[Notification] Erro ao buscar profissionais: %v", err)
		return err
	}

	// 3. Buscar Logística (Carros)
	carros, err := s.queries.ListCarrosByAgendaID(bgCtx, pgtype.UUID{Bytes: agendaID, Valid: true})
	if err != nil {
		log.Printf("[Notification] Erro ao buscar carros: %v", err)
		// Segue sem logística detalhada
	}

	// Struct para passageiro + ID para ordenação
	type PassengerInfo struct {
		ID   string
		Nome string
	}

	// Mapear Passageiros por Carro e Carro por Profissional
	passengersByCar := make(map[uuid.UUID][]PassengerInfo)
	carByProfessional := make(map[uuid.UUID]generated.ListCarrosByAgendaIDRow) // ProfID -> Carro

	for _, carro := range carros {
		// Converter pgtype.UUID para uuid.UUID para usar como chave de mapa
		carUuid := uuid.UUID(carro.ID.Bytes)
		carIDStr := carUuid.String()

		passengers, err := s.queries.ListPassageirosByCarroID(bgCtx, carro.ID)
		if err == nil {
			var pList []PassengerInfo
			for _, p := range passengers {
				pUUID := uuid.UUID(p.ProfissionalID.Bytes)
				pList = append(pList, PassengerInfo{ID: pUUID.String(), Nome: p.Nome})

				if p.ProfissionalID.Valid {
					carByProfessional[pUUID] = carro
				}
			}

			// Sort passengers if order provided
			if passengerOrders != nil {
				if orders, ok := passengerOrders[carIDStr]; ok {
					sort.Slice(pList, func(i, j int) bool {
						ordA := orders[pList[i].ID]
						ordB := orders[pList[j].ID]
						// If order missing (0), push to end? Or treat as 999 equivalent?
						if ordA == 0 {
							ordA = 999
						}
						if ordB == 0 {
							ordB = 999
						}
						if ordA == ordB {
							return pList[i].Nome < pList[j].Nome
						}
						return ordA < ordB
					})
				}
			}

			passengersByCar[carUuid] = pList
		}

		// O motorista também está no carro
		if carro.MotoristaID.Valid {
			driverUuid := uuid.UUID(carro.MotoristaID.Bytes)
			carByProfessional[driverUuid] = carro
		}
	}

	// 4. Enviar Mensagens
	for _, p := range profs {
		// O retorno de GetAgendaProfessionals traz p.*, então o ID é p.ID (cadastro_profissionais.id)
		targetID := uuid.UUID(p.ID.Bytes)

		// Buscar dados completos para ter o whatsapp atualizado (se necessario, mas p.* ja tem whatsapp)
		// Vamos usar p.Whatsapp direto se tiver.
		phone := p.Whatsapp.String
		if phone == "" {
			// Tenta buscar novamente caso GetAgendaProfessionals não trouxer (mas traz p.*)
			continue
		}

		// Montar mensagem de logística
		logisticaMsg := ""
		if carro, ok := carByProfessional[targetID]; ok {
			motorista := carro.NomeMotorista.String
			if carro.MotoristaNomeSistema.Valid {
				motorista = carro.MotoristaNomeSistema.String
			}

			chegada := carro.HorarioChegada.String

			carroUuid := uuid.UUID(carro.ID.Bytes)
			passageirosInfos := passengersByCar[carroUuid]

			// Filtrar o próprio nome para "Outros", mas manter a lista completa para "Rota" se ordenada
			// Se o usuário é passageiro, mostramos a rota completa ou "Você é o Xº"?
			// Melhor mostrar a lista ordenada de todos os passageiros.

			// Se passengerOrders != nil, mostramos Rota Ordenada.
			// Se nil, mostramos "Com: A, B" (Style antigo).

			hasOrder := passengerOrders != nil && len(passengerOrders[carroUuid.String()]) > 0

			listaPassageiros := ""

			if hasOrder {
				listaPassageiros = "\n\n📋 *Ordem de Busca:*"
				foundSelf := false
				for i, passInfo := range passageirosInfos {
					marker := ""
					if passInfo.ID == targetID.String() {
						marker = " (Você)"
						foundSelf = true
					}
					listaPassageiros += fmt.Sprintf("\n%d. %s%s", i+1, passInfo.Nome, marker)
				}
				if !foundSelf {
					// Caso seja o motorista, não aparece na lista de passageiros? ou aparece?
					// ListaPassageiros só tem passageiros. Motorista é separado.
					// Se o alvo é motorista, ele vê a ordem de busca.
					if targetID == uuid.UUID(carro.MotoristaID.Bytes) {
						// Motorista vê a lista
					} else {
						// Passageiro não está na lista? Erro de lógica?
						// pList vem de ListPassageirosByCarroID.
					}
				}
			} else {
				// Legacy list style (excludes self if passenger)
				var outros []string
				for _, passInfo := range passageirosInfos {
					if passInfo.ID != targetID.String() {
						outros = append(outros, passInfo.Nome)
					}
				}

				if len(outros) > 0 {
					listaPassageiros = "\nCom: " + strings.Join(outros, ", ")
				}
			}

			logisticaMsg = fmt.Sprintf("\n\n🚗 *Transporte Definido*\nCarro de: *%s*\nChegada: *%s*%s", motorista, chegada, listaPassageiros)
		} else {
			logisticaMsg = "\n\n🚗 *Transporte:* Verifique no painel ou entre em contato."
		}

		msg := fmt.Sprintf("✅ *Evento Confirmado!* 🚀\n\nOlá *%s*! O evento a seguir foi confirmado e sua escala está valendo.\n\n📅 *%s*\n⏰ *%s*\n📍 *%s*\n📌 *%s*%s\n\nBom trabalho!",
			p.Nome,
			dataFmt,
			horaFmt,
			localFmt,
			tipoEventoNome,
			logisticaMsg,
		)

		if err := s.notification.SendWhatsApp(phone, msg); err != nil {
			// Não logar erro para todos se for falha de validação de numero, mas logar warning
			log.Printf("[Notification] Erro ao enviar para %s: %v", p.Nome, err)
		}
	}

	// Atualizar timestamp da notificação
	if err := s.queries.UpdateLogisticsNotificationTimestamp(bgCtx, pgtype.UUID{Bytes: agendaID, Valid: true}); err != nil {
		log.Printf("[Notification] Erro ao atualizar timestamp: %v", err)
	}

	return nil
}

func (s *Service) UpdateAssignmentStatus(ctx context.Context, agendaID, professionalID uuid.UUID, status string, reason string, regiao string) error {
	// Conflict Validation on Accept
	if status == "ACEITO" {
		// 1. Get Current Agenda to know Date/Time
		agenda, err := s.queries.GetAgenda(ctx, generated.GetAgendaParams{
			ID:     pgtype.UUID{Bytes: agendaID, Valid: true},
			Regiao: pgtype.Text{String: regiao, Valid: true},
		})
		if err != nil {
			return fmt.Errorf("erro ao buscar agenda para validação: %v", err)
		}

		if agenda.DataEvento.Valid {
			// 2. Check for other confirmed events on the same date
			// Exclude current agenda ID from check
			conflicts, err := s.queries.CheckProfessionalBusyDate(ctx, generated.CheckProfessionalBusyDateParams{
				ProfissionalID: pgtype.UUID{Bytes: professionalID, Valid: true},
				DataEvento:     agenda.DataEvento,
				ID:             pgtype.UUID{Bytes: agendaID, Valid: true},
			})
			if err != nil {
				return fmt.Errorf("erro ao verificar disponibilidade: %v", err)
			}

			if len(conflicts) > 0 {
				// 3. Check time overlap
				currentStart := parseTimeMinutes(agenda.Horario.String)
				currentEnd := currentStart + 240 // Assume 4 hours duration

				for _, c := range conflicts {
					conflictStart := parseTimeMinutes(c.Horario.String)
					conflictEnd := conflictStart + 240

					// Check overlap: StartA < EndB && StartB < EndA
					if currentStart < conflictEnd && conflictStart < currentEnd {
						return fmt.Errorf("conflito de horário: profissional já confirmou presença em outro evento às %s", c.Horario.String)
					}
				}

			}

			// --- AUTO-CREATE FINANCIAL TRANSACTION ---
			// 1. Fetch Assignment to know the Function/Role
			assign, err := s.queries.GetAssignment(ctx, generated.GetAssignmentParams{
				AgendaID:       pgtype.UUID{Bytes: agendaID, Valid: true},
				ProfissionalID: pgtype.UUID{Bytes: professionalID, Valid: true},
			})
			if err != nil {
				log.Printf("[AutoFinance] Error fetching assignment: %v", err)
			} else {
				// 2. Determine Service Name
				var serviceName string
				if assign.FuncaoID.Valid {
					fn, err := s.queries.GetFuncaoByID(ctx, assign.FuncaoID)
					if err == nil {
						serviceName = fn.Nome
					}
				}

				// Fallback to professional's default function
				prof, errProf := s.queries.GetProfissionalByID(ctx, generated.GetProfissionalByIDParams{
					ID:     pgtype.UUID{Bytes: professionalID, Valid: true},
					Regiao: pgtype.Text{String: regiao, Valid: true},
				})
				if serviceName == "" && errProf == nil && prof.FuncaoProfissionalID.Valid {
					fn, err := s.queries.GetFuncaoByID(ctx, prof.FuncaoProfissionalID)
					if err == nil {
						serviceName = fn.Nome
					}
				}

				// 3. Fetch Event Type Name
				tipoEvento, errType := s.queries.GetTipoEventoByID(ctx, generated.GetTipoEventoByIDParams{
					ID:     agenda.TipoEventoID,
					Regiao: pgtype.Text{String: regiao, Valid: true},
				})

				if serviceName != "" && errType == nil && errProf == nil {
					// 4. Fetch Standard Price
					price, errPrice := s.financeService.GetStandardPrice(ctx, tipoEvento.Nome, serviceName, regiao)

					baseValue := 0.0
					var priceNumeric pgtype.Numeric
					if errPrice == nil {
						priceNumeric = price
						if val, err := price.Float64Value(); err == nil && val.Valid {
							baseValue = val.Float64
						}
					} else {
						log.Printf("[AutoFinance] Price not found for %s / %s: %v", tipoEvento.Nome, serviceName, errPrice)
						// We continue with 0.0 or handle error?
						// User wants it to appear. If 0, it appears as 0.
						priceNumeric.Scan("0")
					}

					// 5. Create Transaction
					// Check if already exists? (Optional, but good practice. For now simpler is better)

					_, errCreate := s.financeService.Create(ctx, generated.CreateTransactionParams{
						FotID:            agenda.FotID,
						DataCobranca:     agenda.DataEvento,
						TipoEvento:       pgtype.Text{String: tipoEvento.Nome, Valid: true},
						TipoServico:      pgtype.Text{String: serviceName, Valid: true},
						ProfessionalName: pgtype.Text{String: prof.Nome, Valid: true},
						Whatsapp:         prof.Whatsapp,
						Cpf:              prof.CpfCnpjTitular,
						TotalPagar:       priceNumeric, // Base Value
						ValorFree:        priceNumeric, // Populate Free value for frontend calc
						ProfissionalID:   pgtype.UUID{Bytes: professionalID, Valid: true},
						PgtoOk:           pgtype.Bool{Bool: false, Valid: true},
						// Others default/null
					}, regiao)

					if errCreate != nil {
						log.Printf("[AutoFinance] Failed to create transaction: %v", errCreate)
					} else {
						log.Printf("[AutoFinance] Transaction created for %s: %.2f", prof.Nome, baseValue)
					}
				}
			}
		}
	}

	params := generated.UpdateAssignmentStatusParams{
		AgendaID:       pgtype.UUID{Bytes: agendaID, Valid: true},
		ProfissionalID: pgtype.UUID{Bytes: professionalID, Valid: true},
		Status:         pgtype.Text{String: status, Valid: true},
		MotivoRejeicao: pgtype.Text{String: reason, Valid: reason != ""},
	}
	_, err := s.queries.UpdateAssignmentStatus(ctx, params)
	return err
}

// Helper for time parsing (HH:MM)
func parseTimeMinutes(t string) int {
	if len(t) < 5 {
		return 0 // Default or Error
	}
	h, _ := strconv.Atoi(t[0:2])
	m, _ := strconv.Atoi(t[3:5])
	return h*60 + m
}

func (s *Service) UpdateAssignmentPosition(ctx context.Context, agendaID, professionalID uuid.UUID, posicao string) error {
	params := generated.UpdateAssignmentPositionParams{
		AgendaID:       pgtype.UUID{Bytes: agendaID, Valid: true},
		ProfissionalID: pgtype.UUID{Bytes: professionalID, Valid: true},
		Posicao:        pgtype.Text{String: posicao, Valid: true},
	}
	_, err := s.queries.UpdateAssignmentPosition(ctx, params)
	return err
}

func (s *Service) ListAvailableProfessionals(ctx context.Context, date time.Time, regiao string) ([]generated.ListAvailableProfessionalsForDateRow, error) {
	return s.queries.ListAvailableProfessionalsForDate(ctx, generated.ListAvailableProfessionalsForDateParams{
		Data:   pgtype.Date{Time: date, Valid: true},
		Regiao: pgtype.Text{String: regiao, Valid: true},
	})
}

type FinancialStatementResponse struct {
	TotalRecebido         float64                   `json:"total_recebido"`
	PagamentosConfirmados float64                   `json:"pagamentos_confirmados"`
	PagamentosPendentes   float64                   `json:"pagamentos_pendentes"`
	Transactions          []FinancialTransactionDTO `json:"transactions"`
}

type FinancialTransactionDTO struct {
	ID             uuid.UUID `json:"id"`
	DataEvento     string    `json:"data_evento"`
	NomeEvento     string    `json:"nome_evento"` // Fot + Tipo
	TipoEvento     string    `json:"tipo_evento"`
	Empresa        string    `json:"empresa"`
	ValorRecebido  float64   `json:"valor_recebido"`
	ValorFree      float64   `json:"valor_free"`
	ValorExtra     float64   `json:"valor_extra"`
	DescricaoExtra string    `json:"descricao_extra"`
	DataPagamento  string    `json:"data_pagamento"`
	Status         string    `json:"status"`
}

func (s *Service) GetProfessionalFinancialStatement(ctx context.Context, userID uuid.UUID) (*FinancialStatementResponse, error) {
	// 1. Identificar o profissional logado
	prof, err := s.queries.GetProfissionalByUsuarioID(ctx, pgtype.UUID{Bytes: userID, Valid: true})
	if err != nil {
		return &FinancialStatementResponse{}, fmt.Errorf("profissional não encontrado para este usuário")
	}

	profID := pgtype.UUID{Bytes: prof.ID.Bytes, Valid: true}
	cpf := prof.CpfCnpjTitular.String // Fallback para registros antigos

	// 2. Buscar Transações
	rawTransactions, err := s.queries.ListTransactionsByProfessional(ctx, generated.ListTransactionsByProfessionalParams{
		ProfissionalID: profID,
		Column2:        cpf,
	})
	if err != nil {
		// Se não houver transações, retorna vazio sem erro
		return &FinancialStatementResponse{}, nil
	}

	// 3. Processar e Somar

	var response FinancialStatementResponse
	var dtoList []FinancialTransactionDTO

	for _, t := range rawTransactions {
		// Validar valores
		valor := 0.0
		valTotal, _ := t.TotalPagar.Float64Value() // pgtype.Numeric
		if valTotal.Valid {
			valor = valTotal.Float64
		}

		fmt.Printf("DEBUG Transaction %v: Total=%.2f Free=%.2f Extra=%.2f Desc=%s\n",
			t.ID, valor, getFloat64(t.ValorFree), getFloat64(t.ValorExtra), t.DescricaoExtra.String)

		// Status e Somatórios
		status := "Pendente"
		if t.PgtoOk.Valid && t.PgtoOk.Bool {
			status = "Pago"
			response.TotalRecebido += valor
			response.PagamentosConfirmados += valor // Assumindo Recebido = Confirmado neste contexto
		} else {
			response.PagamentosPendentes += valor
		}

		// Formatar Dados
		dataEvento := ""
		if t.DataCobranca.Valid {
			dataEvento = t.DataCobranca.Time.Format("02/01/2006")
		}

		dtPagamento := "-"
		if t.DataPagamento.Valid {
			dtPagamento = t.DataPagamento.Time.Format("02/01/2006")
		}

		empresa := "-"
		if t.EmpresaNome.Valid {
			empresa = t.EmpresaNome.String
		}

		nomeEvento := ""
		if t.FotNumero.Valid {
			if t.CursoNome.Valid {
				nomeEvento = fmt.Sprintf("Formatura %s (FOT %s)", t.CursoNome.String, t.FotNumero.String)
			} else {
				nomeEvento = fmt.Sprintf("Formatura FOT %s", t.FotNumero.String)
			}
		} else {
			nomeEvento = t.TipoEvento.String
		}

		dto := FinancialTransactionDTO{
			ID:             uuid.UUID(t.ID.Bytes),
			DataEvento:     dataEvento,
			NomeEvento:     nomeEvento,
			TipoEvento:     t.TipoEvento.String,
			Empresa:        empresa,
			ValorRecebido:  valor,
			ValorFree:      getFloat64(t.ValorFree),
			ValorExtra:     getFloat64(t.ValorExtra),
			DescricaoExtra: t.DescricaoExtra.String,
			DataPagamento:  dtPagamento,
			Status:         status,
		}
		dtoList = append(dtoList, dto)
	}

	response.Transactions = dtoList
	return &response, nil
}

func getFloat64(n pgtype.Numeric) float64 {
	v, _ := n.Float64Value()
	if v.Valid {
		return v.Float64
	}
	return 0
}

type ImportAgendaRequest struct {
	Fot               string `json:"fot"`
	Data              string `json:"data"` // DD/MM/YYYY
	TipoEvento        string `json:"tipo_evento"`
	Observacoes       string `json:"observacoes"` // Obs Evento (Column I)
	Local             string `json:"local"`
	Endereco          string `json:"endereco"`
	Horario           string `json:"horario"`
	QtdFormandos      int32  `json:"qtd_formandos"`      // M
	QtdFotografos     int32  `json:"qtd_fotografos"`     // N
	QtdCinegrafistas  int32  `json:"qtd_cinegrafistas"`  // O - Cinegrafista (Screenshot Col O header "cinegrafista"?)
	QtdRecepcionistas int32  `json:"qtd_recepcionistas"` // ? Need mapping from header. Screenshot Col P "Estúdio"?
	// Mapping from Screenshot:
	// M: Formandos -> qtd_formandos
	// N: fotografo -> qtd_fotografos
	// O: cinegrafista -> qtd_cinegrafistas
	// P: Estudio -> qtd_estudios
	// Q: Ponto de Foto -> qtd_ponto_foto
	// R: Ponto de ID -> qtd_ponto_id
	// S: Ponto -> qtd_ponto_decorado (Assumption)
	// T: Pontos Led -> qtd_pontos_led
	// U: Plataforma -> qtd_plataforma_360
	QtdEstudios      int32 `json:"qtd_estudios"`
	QtdPontoFoto     int32 `json:"qtd_ponto_foto"`
	QtdPontoID       int32 `json:"qtd_ponto_id"`
	QtdPontoDecorado int32 `json:"qtd_ponto_decorado"`
	QtdPontosLed     int32 `json:"qtd_pontos_led"`
	QtdPlataforma360 int32 `json:"qtd_plataforma_360"`

	FotoFaltante  int32 `json:"foto_faltante"`
	RecepFaltante int32 `json:"recep_faltante"`
	CineFaltante  int32 `json:"cine_faltante"`

	LogisticaObservacoes string `json:"logistica_observacoes"`
	PreVenda             bool   `json:"pre_venda"`
}

func (s *Service) ImportAgenda(ctx context.Context, userID uuid.UUID, items []ImportAgendaRequest, regiao string) error {
	// 1. Pre-load cache if needed or just query. Query is safer (less race conditions).

	for _, item := range items {
		// Parse Date
		// Helper to parse DD/MM/YYYY
		parsedDate, err := time.Parse("02/01/2006", item.Data)
		if err != nil {
			// Try standard format or log error?
			// Fallback
			parsedDate = time.Now() // Dangerous default, better skip.
			log.Printf("Erro ao parsear data para FOT %s: %v", item.Fot, err)
			continue
		}

		// 1. Find FOT
		// Assume GetCadastroFotByFOT exists in generated.
		fot, err := s.queries.GetCadastroFotByFOT(ctx, generated.GetCadastroFotByFOTParams{
			Fot:    item.Fot,
			Regiao: pgtype.Text{String: regiao, Valid: true},
		})
		if err != nil {
			log.Printf("FOT %s não encontrado. Pulando evento.", item.Fot)
			continue
		}

		// 2. Find/Create Tipo Evento
		tipoEventoID, err := s.findOrCreateTipoEvento(ctx, item.TipoEvento, regiao)
		if err != nil {
			log.Printf("Erro ao processar Tipo Evento %s: %v", item.TipoEvento, err)
			continue
		}

		// 3. Upsert Agenda
		// We will assume that same FOT + Date + Tipo = Same Event
		// We check if exists

		params := generated.CreateAgendaParams{
			FotID:                pgtype.UUID{Bytes: fot.ID.Bytes, Valid: true},
			DataEvento:           pgtype.Date{Time: parsedDate, Valid: true},
			TipoEventoID:         pgtype.UUID{Bytes: tipoEventoID, Valid: true},
			ObservacoesEvento:    pgtype.Text{String: item.Observacoes, Valid: item.Observacoes != ""},
			LocalEvento:          pgtype.Text{String: item.Local, Valid: item.Local != ""},
			Endereco:             pgtype.Text{String: item.Endereco, Valid: item.Endereco != ""},
			Horario:              pgtype.Text{String: item.Horario, Valid: item.Horario != ""},
			QtdFormandos:         pgtype.Int4{Int32: item.QtdFormandos, Valid: true},
			QtdFotografos:        pgtype.Int4{Int32: item.QtdFotografos, Valid: true},
			QtdCinegrafistas:     pgtype.Int4{Int32: item.QtdCinegrafistas, Valid: true},
			QtdRecepcionistas:    pgtype.Int4{Int32: item.QtdRecepcionistas, Valid: true},
			QtdEstudios:          pgtype.Int4{Int32: item.QtdEstudios, Valid: true},
			QtdPontoFoto:         pgtype.Int4{Int32: item.QtdPontoFoto, Valid: true},
			QtdPontoID:           pgtype.Int4{Int32: item.QtdPontoID, Valid: true},
			QtdPontoDecorado:     pgtype.Int4{Int32: item.QtdPontoDecorado, Valid: true},
			QtdPontosLed:         pgtype.Int4{Int32: item.QtdPontosLed, Valid: true},
			QtdPlataforma360:     pgtype.Int4{Int32: item.QtdPlataforma360, Valid: true},
			StatusProfissionais:  pgtype.Text{String: "OK", Valid: true}, // Recalculated below
			FotoFaltante:         pgtype.Int4{Int32: item.FotoFaltante, Valid: true},
			RecepFaltante:        pgtype.Int4{Int32: item.RecepFaltante, Valid: true},
			CineFaltante:         pgtype.Int4{Int32: item.CineFaltante, Valid: true},
			LogisticaObservacoes: pgtype.Text{String: item.LogisticaObservacoes, Valid: item.LogisticaObservacoes != ""},
			PreVenda:             pgtype.Bool{Bool: item.PreVenda, Valid: true},
			UserID:               pgtype.UUID{Bytes: userID, Valid: true},
			Regiao:               pgtype.Text{String: regiao, Valid: true},
		}

		// Recalculate status
		status := s.CalculateStatus(item.FotoFaltante, item.RecepFaltante, item.CineFaltante)
		params.StatusProfissionais = pgtype.Text{String: status, Valid: true}

		// Attempt Upsert (Check existence)
		// Ideally we need UpsertAgenda query in sqlc. Since we don't know if it exists, use Check Logic.
		existing, err := s.queries.GetAgendaByFotDataTipo(ctx, generated.GetAgendaByFotDataTipoParams{
			FotID:        fot.ID,
			DataEvento:   pgtype.Date{Time: parsedDate, Valid: true},
			TipoEventoID: pgtype.UUID{Bytes: tipoEventoID, Valid: true},
			Regiao:       pgtype.Text{String: regiao, Valid: true},
		})

		if err == nil {
			// Update
			updateParams := generated.UpdateAgendaParams{
				ID:                   existing.ID,
				Regiao:               pgtype.Text{String: regiao, Valid: true}, // Added to Update query
				FotID:                params.FotID,
				DataEvento:           params.DataEvento,
				TipoEventoID:         params.TipoEventoID,
				ObservacoesEvento:    params.ObservacoesEvento,
				LocalEvento:          params.LocalEvento,
				Endereco:             params.Endereco,
				Horario:              params.Horario,
				QtdFormandos:         params.QtdFormandos,
				QtdFotografos:        params.QtdFotografos,
				QtdCinegrafistas:     params.QtdCinegrafistas,
				QtdRecepcionistas:    params.QtdRecepcionistas,
				QtdEstudios:          params.QtdEstudios,
				QtdPontoFoto:         params.QtdPontoFoto,
				QtdPontoID:           params.QtdPontoID,
				QtdPontoDecorado:     params.QtdPontoDecorado,
				QtdPontosLed:         params.QtdPontosLed,
				QtdPlataforma360:     params.QtdPlataforma360,
				StatusProfissionais:  params.StatusProfissionais,
				FotoFaltante:         params.FotoFaltante,
				RecepFaltante:        params.RecepFaltante,
				CineFaltante:         params.CineFaltante,
				LogisticaObservacoes: params.LogisticaObservacoes,
				PreVenda:             params.PreVenda,
			}
			s.queries.UpdateAgenda(ctx, updateParams)
		} else {
			// Insert
			s.queries.CreateAgenda(ctx, params)
		}
	}
	return nil
}

func (s *Service) findOrCreateTipoEvento(ctx context.Context, nome string, regiao string) (uuid.UUID, error) {
	if nome == "" {
		nome = "Evento"
	}
	// Check if exists
	te, err := s.queries.GetTipoEventoByNome(ctx, generated.GetTipoEventoByNomeParams{
		Nome:   nome,
		Regiao: pgtype.Text{String: regiao, Valid: true},
	})
	if err == nil {
		return uuid.UUID(te.ID.Bytes), nil
	}

	// Create
	newTe, err := s.queries.CreateTipoEvento(ctx, generated.CreateTipoEventoParams{
		Nome:   nome,
		Regiao: pgtype.Text{String: regiao, Valid: true},
	})
	if err != nil {
		return uuid.Nil, err
	}
	return uuid.UUID(newTe.ID.Bytes), nil
}
