package services import ( "database/sql" "fmt" "time" "github.com/rede5/gohorsejobs/backend/internal/dto" "github.com/rede5/gohorsejobs/backend/internal/models" ) type ApplicationService struct { DB *sql.DB EmailService EmailService } func NewApplicationService(db *sql.DB, emailService EmailService) *ApplicationService { return &ApplicationService{ DB: db, EmailService: emailService, } } func (s *ApplicationService) CreateApplication(req dto.CreateApplicationRequest) (*models.Application, error) { query := ` INSERT INTO applications ( job_id, user_id, name, phone, line_id, whatsapp, email, message, resume_url, documents, status, created_at, updated_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING id, created_at, updated_at ` app := &models.Application{ JobID: req.JobID, UserID: req.UserID, Name: req.Name, Phone: req.Phone, LineID: req.LineID, WhatsApp: req.WhatsApp, Email: req.Email, Message: req.Message, ResumeURL: req.ResumeURL, Documents: req.Documents, Status: "pending", CreatedAt: time.Now(), UpdatedAt: time.Now(), } err := s.DB.QueryRow( query, app.JobID, app.UserID, app.Name, app.Phone, app.LineID, app.WhatsApp, app.Email, app.Message, app.ResumeURL, app.Documents, app.Status, app.CreatedAt, app.UpdatedAt, ).Scan(&app.ID, &app.CreatedAt, &app.UpdatedAt) if err != nil { return nil, err } // Notify Company (Mock) go func() { name := "" if app.Name != nil { name = *app.Name } email := "" if app.Email != nil { email = *app.Email } phone := "" if app.Phone != nil { phone = *app.Phone } subject := fmt.Sprintf("Nova candidatura para a vaga #%s", app.JobID) body := fmt.Sprintf("Olá,\n\nVocê recebeu uma nova candidatura de %s para a vaga #%s.\n\nEmail: %s\nTelefone: %s\n\nVerifique o painel para mais detalhes.", name, app.JobID, email, phone) _ = s.EmailService.SendEmail("company@example.com", subject, body) }() return app, nil } func (s *ApplicationService) GetApplications(jobID string) ([]models.Application, error) { // Simple get by Job ID query := ` SELECT id, job_id, user_id, name, phone, line_id, whatsapp, email, message, resume_url, documents, status, created_at, updated_at FROM applications WHERE job_id = $1 ` rows, err := s.DB.Query(query, jobID) if err != nil { return nil, err } defer rows.Close() var apps []models.Application for rows.Next() { var a models.Application if err := rows.Scan( &a.ID, &a.JobID, &a.UserID, &a.Name, &a.Phone, &a.LineID, &a.WhatsApp, &a.Email, &a.Message, &a.ResumeURL, &a.Documents, &a.Status, &a.CreatedAt, &a.UpdatedAt, ); err != nil { return nil, err } apps = append(apps, a) } return apps, nil } func (s *ApplicationService) ListUserApplications(userID string) ([]models.ApplicationWithDetails, error) { query := ` SELECT a.id, a.job_id, a.user_id, a.name, a.phone, a.line_id, a.whatsapp, a.email, a.message, a.resume_url, a.status, a.created_at, a.updated_at, j.title, c.name FROM applications a JOIN jobs j ON a.job_id = j.id LEFT JOIN companies c ON j.company_id = c.id WHERE a.user_id = $1 ORDER BY a.created_at DESC ` rows, err := s.DB.Query(query, userID) if err != nil { return nil, err } defer rows.Close() var apps []models.ApplicationWithDetails for rows.Next() { var a models.ApplicationWithDetails if err := rows.Scan( &a.ID, &a.JobID, &a.UserID, &a.Name, &a.Phone, &a.LineID, &a.WhatsApp, &a.Email, &a.Message, &a.ResumeURL, &a.Status, &a.CreatedAt, &a.UpdatedAt, &a.JobTitle, &a.CompanyName, ); err != nil { return nil, err } // Some logical defaults if needed a.CompanyID = "" // Adjusted to string from int/empty apps = append(apps, a) } return apps, nil } func (s *ApplicationService) GetApplicationByID(id string) (*models.Application, error) { var a models.Application query := ` SELECT id, job_id, user_id, name, phone, line_id, whatsapp, email, message, resume_url, documents, status, created_at, updated_at FROM applications WHERE id = $1 ` err := s.DB.QueryRow(query, id).Scan( &a.ID, &a.JobID, &a.UserID, &a.Name, &a.Phone, &a.LineID, &a.WhatsApp, &a.Email, &a.Message, &a.ResumeURL, &a.Documents, &a.Status, &a.CreatedAt, &a.UpdatedAt, ) if err != nil { return nil, err } return &a, nil } func (s *ApplicationService) UpdateApplicationStatus(id string, req dto.UpdateApplicationStatusRequest) (*models.Application, error) { query := ` UPDATE applications SET status = $1, updated_at = NOW() WHERE id = $2 RETURNING updated_at ` var updatedAt time.Time err := s.DB.QueryRow(query, req.Status, id).Scan(&updatedAt) if err != nil { return nil, err } return s.GetApplicationByID(id) } func (s *ApplicationService) GetApplicationsByCompany(companyID string) ([]models.Application, error) { query := ` SELECT a.id, a.job_id, a.user_id, a.name, a.phone, a.line_id, a.whatsapp, a.email, a.message, a.resume_url, a.documents, a.status, a.created_at, a.updated_at FROM applications a JOIN jobs j ON a.job_id = j.id WHERE j.company_id = $1 ORDER BY a.created_at DESC ` rows, err := s.DB.Query(query, companyID) if err != nil { return nil, err } defer rows.Close() var apps []models.Application for rows.Next() { var a models.Application if err := rows.Scan( &a.ID, &a.JobID, &a.UserID, &a.Name, &a.Phone, &a.LineID, &a.WhatsApp, &a.Email, &a.Message, &a.ResumeURL, &a.Documents, &a.Status, &a.CreatedAt, &a.UpdatedAt, ); err != nil { return nil, err } apps = append(apps, a) } return apps, nil } func (s *ApplicationService) GetApplicationsByUser(userID string) ([]models.ApplicationWithDetails, error) { query := ` SELECT a.id, a.job_id, a.user_id, a.name, a.phone, a.line_id, a.whatsapp, a.email, a.message, a.resume_url, a.status, a.created_at, a.updated_at, j.title, c.name, j.company_id FROM applications a JOIN jobs j ON a.job_id = j.id LEFT JOIN companies c ON j.company_id::text = c.id::text WHERE a.user_id = $1 ORDER BY a.created_at DESC ` rows, err := s.DB.Query(query, userID) if err != nil { return nil, err } defer rows.Close() var apps []models.ApplicationWithDetails = []models.ApplicationWithDetails{} for rows.Next() { var a models.ApplicationWithDetails var companyID sql.NullString if err := rows.Scan( &a.ID, &a.JobID, &a.UserID, &a.Name, &a.Phone, &a.LineID, &a.WhatsApp, &a.Email, &a.Message, &a.ResumeURL, &a.Status, &a.CreatedAt, &a.UpdatedAt, &a.JobTitle, &a.CompanyName, &companyID, ); err != nil { return nil, err } if companyID.Valid { a.CompanyID = companyID.String } apps = append(apps, a) } return apps, nil } func (s *ApplicationService) DeleteApplication(id string) error { query := `DELETE FROM applications WHERE id = $1` _, err := s.DB.Exec(query, id) return err }