package agenda import ( "context" "encoding/json" "time" "photum-backend/internal/db/generated" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgtype" ) type Service struct { queries *generated.Queries } func NewService(db *generated.Queries) *Service { return &Service{queries: db} } 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"` } type Assignment struct { ProfessionalID string `json:"professional_id"` Status string `json:"status"` MotivoRejeicao *string `json:"motivo_rejeicao"` } type AgendaResponse struct { generated.ListAgendasRow ParsedAssignments []Assignment `json:"assignments"` } 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) (generated.Agenda, error) { status := s.CalculateStatus(req.FotoFaltante, req.RecepFaltante, req.CineFaltante) 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}, } return s.queries.CreateAgenda(ctx, params) } func (s *Service) List(ctx context.Context, userID uuid.UUID, role string) ([]AgendaResponse, error) { var rows []generated.ListAgendasRow var err error // If role is CLIENT (cliente), filter by userID if role == "cliente" || role == "EVENT_OWNER" { listRows, err := s.queries.ListAgendasByUser(ctx, pgtype.UUID{Bytes: userID, Valid: true}) if err != nil { return nil, err } // Convert ListAgendasByUserRow 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, AnoSemestre: r.AnoSemestre, ObservacoesFot: r.ObservacoesFot, TipoEventoNome: r.TipoEventoNome, AssignedProfessionals: r.AssignedProfessionals, }) } } else { rows, err = s.queries.ListAgendas(ctx) if err != nil { return nil, err } } 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) } } response = append(response, AgendaResponse{ ListAgendasRow: row, ParsedAssignments: assignments, }) } return response, nil } func (s *Service) Get(ctx context.Context, id uuid.UUID) (generated.Agenda, error) { return s.queries.GetAgenda(ctx, pgtype.UUID{Bytes: id, Valid: true}) } func (s *Service) Update(ctx context.Context, id uuid.UUID, req CreateAgendaRequest) (generated.Agenda, error) { status := s.CalculateStatus(req.FotoFaltante, req.RecepFaltante, req.CineFaltante) 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}, } return s.queries.UpdateAgenda(ctx, params) } func (s *Service) Delete(ctx context.Context, id uuid.UUID) error { return s.queries.DeleteAgenda(ctx, pgtype.UUID{Bytes: id, Valid: true}) } func (s *Service) AssignProfessional(ctx context.Context, agendaID uuid.UUID, profID uuid.UUID) error { params := generated.AssignProfessionalParams{ AgendaID: pgtype.UUID{Bytes: agendaID, Valid: true}, ProfissionalID: pgtype.UUID{Bytes: profID, Valid: true}, } return s.queries.AssignProfessional(ctx, params) } 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) (generated.Agenda, error) { params := generated.UpdateAgendaStatusParams{ ID: pgtype.UUID{Bytes: agendaID, Valid: true}, Status: pgtype.Text{String: status, Valid: true}, } return s.queries.UpdateAgendaStatus(ctx, params) } func (s *Service) UpdateAssignmentStatus(ctx context.Context, agendaID, professionalID uuid.UUID, status string, reason string) error { 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 }