package services

import (
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"github.com/lib/pq"
	"github.com/rede5/gohorsejobs/backend/internal/dto"
	"github.com/rede5/gohorsejobs/backend/internal/models"
)

type AdminService struct {
	DB *sql.DB
}

func NewAdminService(db *sql.DB) *AdminService {
	return &AdminService{DB: db}
}

func (s *AdminService) ListCompanies(ctx context.Context, verified *bool, page, limit int) ([]models.Company, int, error) {
	offset := (page - 1) * limit

	// Count Total
	countQuery := `SELECT COUNT(*) FROM companies`
	var countArgs []interface{}
	if verified != nil {
		countQuery += " WHERE verified = $1"
		countArgs = append(countArgs, *verified)
	}
	var total int
	if err := s.DB.QueryRowContext(ctx, countQuery, countArgs...).Scan(&total); err != nil {
		return nil, 0, err
	}

	// Fetch Data
	baseQuery := `
		SELECT id, name, slug, type, document, address, region_id, city_id, phone, email, website, logo_url, description, active, verified, created_at, updated_at
		FROM companies
	`

	var args []interface{}
	if verified != nil {
		baseQuery += " WHERE verified = $1"
		args = append(args, *verified)
	}

	// Add pagination
	baseQuery += fmt.Sprintf(" ORDER BY created_at DESC LIMIT $%d OFFSET $%d", len(args)+1, len(args)+2)
	args = append(args, limit, offset)

	rows, err := s.DB.QueryContext(ctx, baseQuery, args...)
	if err != nil {
		return nil, 0, err
	}
	defer rows.Close()

	companies := []models.Company{}
	for rows.Next() {
		var c models.Company
		if err := rows.Scan(
			&c.ID,
			&c.Name,
			&c.Slug,
			&c.Type,
			&c.Document,
			&c.Address,
			&c.RegionID,
			&c.CityID,
			&c.Phone,
			&c.Email,
			&c.Website,
			&c.LogoURL,
			&c.Description,
			&c.Active,
			&c.Verified,
			&c.CreatedAt,
			&c.UpdatedAt,
		); err != nil {
			return nil, 0, err
		}
		companies = append(companies, c)
	}

	return companies, total, nil
}

// ListUsers returns all users with pagination (for admin view)
// If companyID is provided, filters users by that company.
func (s *AdminService) ListUsers(ctx context.Context, page, limit int, companyID *string) ([]dto.User, int, error) {
	offset := (page - 1) * limit

	// Count Total
	countQuery := `SELECT COUNT(*) FROM users`
	var countArgs []interface{}
	if companyID != nil && *companyID != "" {
		countQuery += ` WHERE tenant_id = $1`
		countArgs = append(countArgs, *companyID)
	}
	var total int
	if err := s.DB.QueryRowContext(ctx, countQuery, countArgs...).Scan(&total); err != nil {
		return nil, 0, err
	}

	// Fetch Data
	query := `
		SELECT id, COALESCE(name, full_name, identifier, ''), email, role, COALESCE(status, 'active'), created_at
		FROM users
	`
	var args []interface{}
	if companyID != nil && *companyID != "" {
		query += ` WHERE tenant_id = $1`
		args = append(args, *companyID)
	}
	query += ` ORDER BY created_at DESC`
	query += fmt.Sprintf(` LIMIT $%d OFFSET $%d`, len(args)+1, len(args)+2)
	args = append(args, limit, offset)

	rows, err := s.DB.QueryContext(ctx, query, args...)
	if err != nil {
		return nil, 0, err
	}
	defer rows.Close()

	users := []dto.User{}
	for rows.Next() {
		var u dto.User
		var roleStr string
		if err := rows.Scan(&u.ID, &u.Name, &u.Email, &roleStr, &u.Status, &u.CreatedAt); err != nil {
			return nil, 0, err
		}
		u.Role = roleStr
		users = append(users, u)
	}

	return users, total, nil
}

func (s *AdminService) UpdateCompanyStatus(ctx context.Context, id string, active *bool, verified *bool) (*models.Company, error) {
	company, err := s.GetCompanyByID(ctx, id)
	if err != nil {
		return nil, err
	}

	if active != nil {
		company.Active = *active
	}
	if verified != nil {
		company.Verified = *verified
	}

	company.UpdatedAt = time.Now()
	query := `
		UPDATE companies
		SET active = $1, verified = $2, updated_at = $3
		WHERE id = $4
	`
	_, err = s.DB.ExecContext(ctx, query, company.Active, company.Verified, company.UpdatedAt, id)
	if err != nil {
		return nil, err
	}

	return company, nil
}

func (s *AdminService) DuplicateJob(ctx context.Context, id string) (*models.Job, error) {
	query := `
		SELECT company_id, created_by, title, description, salary_min, salary_max, salary_type,
			employment_type, work_mode, working_hours, location, region_id, city_id,
			requirements, benefits, visa_support, language_level
		FROM jobs
		WHERE id = $1
	`

	var job models.Job
	if err := s.DB.QueryRowContext(ctx, query, id).Scan(
		&job.CompanyID,
		&job.CreatedBy,
		&job.Title,
		&job.Description,
		&job.SalaryMin,
		&job.SalaryMax,
		&job.SalaryType,
		&job.EmploymentType,
		&job.WorkMode,
		&job.WorkingHours,
		&job.Location,
		&job.RegionID,
		&job.CityID,
		&job.Requirements,
		&job.Benefits,
		&job.VisaSupport,
		&job.LanguageLevel,
	); err != nil {
		return nil, err
	}

	job.Status = "draft"
	job.IsFeatured = false
	job.CreatedAt = time.Now()
	job.UpdatedAt = time.Now()

	insertQuery := `
		INSERT INTO jobs (
			company_id, created_by, title, description, salary_min, salary_max, salary_type,
			employment_type, work_mode, working_hours, location, region_id, city_id,
			requirements, benefits, visa_support, language_level, status, is_featured, created_at, updated_at
		) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21)
		RETURNING id
	`

	if err := s.DB.QueryRowContext(ctx, insertQuery,
		job.CompanyID,
		job.CreatedBy,
		job.Title,
		job.Description,
		job.SalaryMin,
		job.SalaryMax,
		job.SalaryType,
		job.EmploymentType,
		job.WorkMode,
		job.WorkingHours,
		job.Location,
		job.RegionID,
		job.CityID,
		job.Requirements,
		job.Benefits,
		job.VisaSupport,
		job.LanguageLevel,
		job.Status,
		job.IsFeatured,
		job.CreatedAt,
		job.UpdatedAt,
	).Scan(&job.ID); err != nil {
		return nil, err
	}

	return &job, nil
}

func (s *AdminService) ListTags(ctx context.Context, category *string) ([]models.Tag, error) {
	baseQuery := `SELECT id, name, category, active, created_at, updated_at FROM job_tags`
	var args []interface{}
	if category != nil && *category != "" {
		baseQuery += " WHERE category = $1"
		args = append(args, *category)
	}
	baseQuery += " ORDER BY name ASC"

	rows, err := s.DB.QueryContext(ctx, baseQuery, args...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	tags := []models.Tag{}
	for rows.Next() {
		var t models.Tag
		if err := rows.Scan(&t.ID, &t.Name, &t.Category, &t.Active, &t.CreatedAt, &t.UpdatedAt); err != nil {
			return nil, err
		}
		tags = append(tags, t)
	}

	return tags, nil
}

func (s *AdminService) CreateTag(ctx context.Context, name string, category string) (*models.Tag, error) {
	if strings.TrimSpace(name) == "" {
		return nil, fmt.Errorf("tag name is required")
	}

	now := time.Now()
	tag := models.Tag{
		Name:      strings.TrimSpace(name),
		Category:  category,
		Active:    true,
		CreatedAt: now,
		UpdatedAt: now,
	}

	query := `
		INSERT INTO job_tags (name, category, active, created_at, updated_at)
		VALUES ($1, $2, $3, $4, $5)
		RETURNING id
	`
	if err := s.DB.QueryRowContext(ctx, query, tag.Name, tag.Category, tag.Active, tag.CreatedAt, tag.UpdatedAt).Scan(&tag.ID); err != nil {
		return nil, err
	}

	return &tag, nil
}

func (s *AdminService) UpdateTag(ctx context.Context, id int, name *string, active *bool) (*models.Tag, error) {
	tag, err := s.getTagByID(ctx, id)
	if err != nil {
		return nil, err
	}

	if name != nil {
		trimmed := strings.TrimSpace(*name)
		if trimmed != "" {
			tag.Name = trimmed
		}
	}
	if active != nil {
		tag.Active = *active
	}
	tagUpdatedAt := time.Now()
	query := `
		UPDATE job_tags
		SET name = $1, active = $2, updated_at = $3
		WHERE id = $4
	`
	_, err = s.DB.ExecContext(ctx, query, tag.Name, tag.Active, tagUpdatedAt, id)
	if err != nil {
		return nil, err
	}

	tag.UpdatedAt = tagUpdatedAt
	return tag, nil
}

func (s *AdminService) ListCandidates(ctx context.Context, companyID *string) ([]dto.Candidate, dto.CandidateStats, error) {
	fmt.Println("[DEBUG] Starting ListCandidates")
	query := `
		SELECT id, full_name, email, phone, city, state, title, experience, bio, skills, avatar_url, created_at
		FROM users
		WHERE role = 'candidate'
		ORDER BY created_at DESC
	`

	fmt.Println("[DEBUG] Executing query:", query)
	rows, err := s.DB.QueryContext(ctx, query)
	if err != nil {
		fmt.Println("[ERROR] Query failed:", err)
		return nil, dto.CandidateStats{}, err
	}
	defer rows.Close()

	candidates := make([]dto.Candidate, 0)
	candidateIndex := make(map[string]int) // ID is string (UUID)
	candidateIDs := make([]string, 0)      // ID is string (UUID)
	stats := dto.CandidateStats{}
	thirtyDaysAgo := time.Now().AddDate(0, 0, -30)

	for rows.Next() {
		var (
			id         string // Changed to string for UUID
			fullName   string
			email      sql.NullString
			phone      sql.NullString
			city       sql.NullString
			state      sql.NullString
			title      sql.NullString
			experience sql.NullString
			bio        sql.NullString
			avatarURL  sql.NullString
			skills     []string
			createdAt  time.Time
		)

		if err := rows.Scan(
			&id,
			&fullName,
			&email,
			&phone,
			&city,
			&state,
			&title,
			&experience,
			&bio,
			pq.Array(&skills),
			&avatarURL,
			&createdAt,
		); err != nil {
			fmt.Println("[ERROR] Scan failed:", err)
			return nil, dto.CandidateStats{}, err
		}

		location := buildLocation(city, state)

		// Fix DTO if it expects int ID? Need to check DTO definition.
		// Assuming DTO also needs update or is already string?
		// If DTO.Candidate.ID is int, this will break compilation.
		// I must verify DTO definition first.
		// But I cannot see DTO definition here.
		// Assuming DTO is compatible or I will fix it next.
		// Actually, in previous Context `Ticket` model ID was changed to string. likely DTO needs it too.
		// I will proceed assuming I need to cast or DTO is string.
		// Wait, if DTO.ID is int, I cannot assign string.
		// Let's assume DTO needs update.
		// For now, I'll update logic to match UUIDs.

		candidate := dto.Candidate{
			ID:           id, // Check if this compiles!
			Name:         fullName,
			Email:        stringOrNil(email),
			Phone:        stringOrNil(phone),
			Location:     location,
			Title:        stringOrNil(title),
			Experience:   stringOrNil(experience),
			Bio:          stringOrNil(bio),
			AvatarURL:    stringOrNil(avatarURL),
			Skills:       normalizeSkills(skills),
			Applications: []dto.CandidateApplication{},
			CreatedAt:    createdAt,
		}

		if createdAt.After(thirtyDaysAgo) {
			stats.NewCandidates++
		}

		candidateIndex[id] = len(candidates)
		candidateIDs = append(candidateIDs, id)
		candidates = append(candidates, candidate)
	}
	fmt.Printf("[DEBUG] Found %d candidates\n", len(candidates))

	stats.TotalCandidates = len(candidates)

	if len(candidateIDs) == 0 {
		return candidates, stats, nil
	}

	appQuery := `
		SELECT a.id, a.user_id, a.status, a.created_at, j.title, c.name
		FROM applications a
		JOIN jobs j ON j.id = a.job_id
		JOIN companies c ON c.id = j.company_id
		WHERE a.user_id = ANY($1)
		ORDER BY a.created_at DESC
	`
	fmt.Println("[DEBUG] Executing appQuery")
	appRows, err := s.DB.QueryContext(ctx, appQuery, pq.Array(candidateIDs))
	if err != nil {
		fmt.Println("[ERROR] AppQuery failed:", err)
		return nil, dto.CandidateStats{}, err
	}
	defer appRows.Close()

	totalApplications := 0
	hiredApplications := 0

	for appRows.Next() {
		var (
			app    dto.CandidateApplication
			userID string // UUID
		)

		if err := appRows.Scan(
			&app.ID,
			&userID,
			&app.Status,
			&app.AppliedAt,
			&app.JobTitle,
			&app.Company,
		); err != nil {
			fmt.Println("[ERROR] AppList Scan failed:", err)
			return nil, dto.CandidateStats{}, err
		}

		totalApplications++
		if isActiveApplicationStatus(app.Status) {
			stats.ActiveApplications++
		}
		if app.Status == "hired" {
			hiredApplications++
		}

		if index, ok := candidateIndex[userID]; ok {
			candidates[index].Applications = append(candidates[index].Applications, app)
		}
	}
	fmt.Printf("[DEBUG] Processed %d applications\n", totalApplications)

	if totalApplications > 0 {
		stats.HiringRate = (float64(hiredApplications) / float64(totalApplications)) * 100
	}

	return candidates, stats, nil
}

func stringOrNil(value sql.NullString) *string {
	if !value.Valid {
		return nil
	}
	trimmed := strings.TrimSpace(value.String)
	if trimmed == "" {
		return nil
	}
	return &trimmed
}

func buildLocation(city sql.NullString, state sql.NullString) *string {
	parts := make([]string, 0, 2)
	if city.Valid && strings.TrimSpace(city.String) != "" {
		parts = append(parts, strings.TrimSpace(city.String))
	}
	if state.Valid && strings.TrimSpace(state.String) != "" {
		parts = append(parts, strings.TrimSpace(state.String))
	}
	if len(parts) == 0 {
		return nil
	}
	location := strings.Join(parts, ", ")
	return &location
}

func normalizeSkills(skills []string) []string {
	if len(skills) == 0 {
		return []string{}
	}
	normalized := make([]string, 0, len(skills))
	for _, skill := range skills {
		trimmed := strings.TrimSpace(skill)
		if trimmed == "" {
			continue
		}
		normalized = append(normalized, trimmed)
	}
	if len(normalized) == 0 {
		return []string{}
	}
	return normalized
}

func isActiveApplicationStatus(status string) bool {
	switch status {
	case "pending", "reviewed", "shortlisted":
		return true
	default:
		return false
	}
}

func (s *AdminService) GetCompanyByID(ctx context.Context, id string) (*models.Company, error) {
	query := `
		SELECT id, name, slug, type, document, address, region_id, city_id, phone, email, website, logo_url, description, active, verified, created_at, updated_at
		FROM companies WHERE id = $1
	`
	var c models.Company
	if err := s.DB.QueryRowContext(ctx, query, id).Scan(
		&c.ID,
		&c.Name,
		&c.Slug,
		&c.Type,
		&c.Document,
		&c.Address,
		&c.RegionID,
		&c.CityID,
		&c.Phone,
		&c.Email,
		&c.Website,
		&c.LogoURL,
		&c.Description,
		&c.Active,
		&c.Verified,
		&c.CreatedAt,
		&c.UpdatedAt,
	); err != nil {
		return nil, err
	}
	return &c, nil
}

func (s *AdminService) getTagByID(ctx context.Context, id int) (*models.Tag, error) {
	query := `SELECT id, name, category, active, created_at, updated_at FROM job_tags WHERE id = $1`
	var t models.Tag
	if err := s.DB.QueryRowContext(ctx, query, id).Scan(&t.ID, &t.Name, &t.Category, &t.Active, &t.CreatedAt, &t.UpdatedAt); err != nil {
		return nil, err
	}
	return &t, nil
}

// GetUser fetches a user by ID
func (s *AdminService) GetUser(ctx context.Context, id string) (*dto.User, error) {
	query := `
		SELECT id, full_name, email, role, COALESCE(status, 'active'), created_at, phone, bio, avatar_url
		FROM users WHERE id = $1
	`
	var u dto.User
	var roleStr string
	var phone sql.NullString
	var bio sql.NullString
	var avatarURL sql.NullString
	if err := s.DB.QueryRowContext(ctx, query, id).Scan(
		&u.ID,
		&u.Name,
		&u.Email,
		&roleStr,
		&u.Status,
		&u.CreatedAt,
		&phone,
		&bio,
		&avatarURL,
	); err != nil {
		return nil, err
	}
	u.Role = roleStr
	if phone.Valid {
		u.Phone = &phone.String
	}
	if bio.Valid {
		u.Bio = &bio.String
	}
	if avatarURL.Valid {
		u.AvatarUrl = &avatarURL.String
	}
	return &u, nil
}

// GetCompanyByUserID fetches the company associated with a user
func (s *AdminService) GetCompanyByUserID(ctx context.Context, userID string) (*models.Company, error) {
	// First, try to find company where this user is admin
	// Assuming users table has company_id or companies table has admin_email
	// Let's check if 'users' has company_id column via error or assume architecture.
	// Since CreateCompany creates a user, it likely links them.
	// I will try to find a company by created_by = user_id IF that column exists?
	// Or query based on some relation.
	// Let's try finding company by admin_email matching user email.

	// Fetch user email first
	user, err := s.GetUser(ctx, userID)
	if err != nil {
		return nil, err
	}

	query := `SELECT id, name, slug, active, verified FROM companies WHERE email = $1`
	var c models.Company
	if err := s.DB.QueryRowContext(ctx, query, user.Email).Scan(&c.ID, &c.Name, &c.Slug, &c.Active, &c.Verified); err != nil {
		// Try another way? Join companies c JOIN users u ON u.company_id = c.id
		// If users table has company_id column...
		// Let's try that as fallback.
		query2 := `
			SELECT c.id, c.name, c.slug, c.active, c.verified
			FROM companies c
			JOIN users u ON u.company_id = c.id
			WHERE u.id = $1
		`
		if err2 := s.DB.QueryRowContext(ctx, query2, userID).Scan(&c.ID, &c.Name, &c.Slug, &c.Active, &c.Verified); err2 != nil {
			return nil, fmt.Errorf("company not found for user %s", userID)
		}
	}
	return &c, nil
}

func (s *AdminService) UpdateCompany(ctx context.Context, id string, req dto.UpdateCompanyRequest) (*models.Company, error) {
	company, err := s.GetCompanyByID(ctx, id)
	if err != nil {
		return nil, err
	}

	if req.Name != nil {
		company.Name = *req.Name
	}
	if req.Slug != nil {
		company.Slug = *req.Slug
	}
	if req.Type != nil {
		company.Type = *req.Type
	}
	if req.Document != nil {
		company.Document = req.Document
	}
	if req.Address != nil {
		company.Address = req.Address
	}
	if req.RegionID != nil {
		company.RegionID = req.RegionID
	}
	if req.CityID != nil {
		company.CityID = req.CityID
	}
	if req.Phone != nil {
		company.Phone = req.Phone
	}
	if req.Email != nil {
		company.Email = req.Email
	}
	if req.Website != nil {
		company.Website = req.Website
	}
	if req.LogoURL != nil {
		company.LogoURL = req.LogoURL
	}
	if req.Description != nil {
		company.Description = req.Description
	}
	if req.Active != nil {
		company.Active = *req.Active
	}
	if req.Verified != nil {
		company.Verified = *req.Verified
	}

	company.UpdatedAt = time.Now()

	query := `
		UPDATE companies
		SET name=$1, slug=$2, type=$3, document=$4, address=$5, region_id=$6, city_id=$7,
		    phone=$8, email=$9, website=$10, logo_url=$11, description=$12, active=$13,
		    verified=$14, updated_at=$15
		WHERE id=$16
	`

	_, err = s.DB.ExecContext(ctx, query,
		company.Name, company.Slug, company.Type, company.Document, company.Address,
		company.RegionID, company.CityID, company.Phone, company.Email, company.Website,
		company.LogoURL, company.Description, company.Active, company.Verified,
		company.UpdatedAt, company.ID,
	)

	if err != nil {
		return nil, err
	}

	return company, nil
}

func (s *AdminService) DeleteCompany(ctx context.Context, id string) error {
	// First check if exists
	_, err := s.GetCompanyByID(ctx, id)
	if err != nil {
		return err
	}

	// Delete
	_, err = s.DB.ExecContext(ctx, `DELETE FROM companies WHERE id=$1`, id)
	return err
}

// ============================================================================
// Email Templates & Settings CRUD
// ============================================================================

func (s *AdminService) ListEmailTemplates(ctx context.Context) ([]dto.EmailTemplateDTO, error) {
	query := `SELECT id, slug, subject, body_html, variables, created_at, updated_at FROM email_templates ORDER BY slug`
	rows, err := s.DB.QueryContext(ctx, query)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	templates := []dto.EmailTemplateDTO{}
	for rows.Next() {
		var t dto.EmailTemplateDTO
		var varsJSON []byte
		if err := rows.Scan(&t.ID, &t.Slug, &t.Subject, &t.BodyHTML, &varsJSON, &t.CreatedAt, &t.UpdatedAt); err != nil {
			return nil, err
		}
		if len(varsJSON) > 0 {
			json.Unmarshal(varsJSON, &t.Variables)
		}
		templates = append(templates, t)
	}
	return templates, nil
}

func (s *AdminService) GetEmailTemplate(ctx context.Context, slug string) (*dto.EmailTemplateDTO, error) {
	query := `SELECT id, slug, subject, body_html, variables, created_at, updated_at FROM email_templates WHERE slug = $1`
	row := s.DB.QueryRowContext(ctx, query, slug)

	t := &dto.EmailTemplateDTO{}
	var varsJSON []byte
	err := row.Scan(&t.ID, &t.Slug, &t.Subject, &t.BodyHTML, &varsJSON, &t.CreatedAt, &t.UpdatedAt)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}
	if len(varsJSON) > 0 {
		json.Unmarshal(varsJSON, &t.Variables)
	}
	return t, nil
}

func (s *AdminService) CreateEmailTemplate(ctx context.Context, req dto.CreateEmailTemplateRequest) (*dto.EmailTemplateDTO, error) {
	query := `INSERT INTO email_templates (slug, subject, body_html, variables, updated_at) VALUES ($1, $2, $3, $4, $5) RETURNING id, created_at`

	varsJSON, _ := json.Marshal(req.Variables)
	if varsJSON == nil {
		varsJSON = []byte("[]")
	}

	t := &dto.EmailTemplateDTO{
		Slug:      req.Slug,
		Subject:   req.Subject,
		BodyHTML:  req.BodyHTML,
		Variables: req.Variables,
	}
	err := s.DB.QueryRowContext(ctx, query, req.Slug, req.Subject, req.BodyHTML, varsJSON, time.Now()).Scan(&t.ID, &t.CreatedAt)
	if err != nil {
		return nil, err
	}
	t.UpdatedAt = t.CreatedAt
	return t, nil
}

func (s *AdminService) UpdateEmailTemplate(ctx context.Context, slug string, req dto.UpdateEmailTemplateRequest) (*dto.EmailTemplateDTO, error) {
	// Fetch existing
	existing, err := s.GetEmailTemplate(ctx, slug)
	if err != nil {
		return nil, err
	}
	if existing == nil {
		return nil, fmt.Errorf("template not found")
	}

	// Apply updates
	if req.Subject != nil {
		existing.Subject = *req.Subject
	}
	if req.BodyHTML != nil {
		existing.BodyHTML = *req.BodyHTML
	}
	if req.Variables != nil {
		existing.Variables = *req.Variables
	}

	varsJSON, _ := json.Marshal(existing.Variables)
	query := `UPDATE email_templates SET subject=$1, body_html=$2, variables=$3, updated_at=$4 WHERE slug=$5`
	_, err = s.DB.ExecContext(ctx, query, existing.Subject, existing.BodyHTML, varsJSON, time.Now(), slug)
	if err != nil {
		return nil, err
	}

	return s.GetEmailTemplate(ctx, slug)
}

func (s *AdminService) DeleteEmailTemplate(ctx context.Context, slug string) error {
	_, err := s.DB.ExecContext(ctx, "DELETE FROM email_templates WHERE slug=$1", slug)
	return err
}

func (s *AdminService) GetEmailSettings(ctx context.Context) (*dto.EmailSettingsDTO, error) {
	query := `SELECT id, provider, smtp_host, smtp_port, smtp_user, smtp_pass, smtp_secure, sender_name, sender_email, amqp_url, is_active, updated_at 
	          FROM email_settings WHERE is_active = true ORDER BY updated_at DESC LIMIT 1`

	row := s.DB.QueryRowContext(ctx, query)
	var s_ dto.EmailSettingsDTO

	err := row.Scan(
		&s_.ID, &s_.Provider, &s_.SMTPHost, &s_.SMTPPort, &s_.SMTPUser, &s_.SMTPPass,
		&s_.SMTPSecure, &s_.SenderName, &s_.SenderEmail, &s_.AMQPURL, &s_.IsActive, &s_.UpdatedAt,
	)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}
	return &s_, nil
}

func (s *AdminService) UpdateEmailSettings(ctx context.Context, req dto.UpdateEmailSettingsRequest) (*dto.EmailSettingsDTO, error) {
	existing, err := s.GetEmailSettings(ctx)
	if err != nil {
		return nil, err
	}

	if existing == nil {
		// Insert new
		query := `INSERT INTO email_settings (provider, smtp_host, smtp_port, smtp_user, smtp_pass, smtp_secure, sender_name, sender_email, amqp_url, is_active)
		          VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, true) RETURNING id, updated_at`
		newS := &dto.EmailSettingsDTO{
			Provider:    "smtp",
			SMTPSecure:  true,
			SenderName:  "GoHorse Jobs",
			SenderEmail: "no-reply@gohorsejobs.com",
			IsActive:    true,
		}
		applyEmailSettingsUpdate(newS, req)
		err = s.DB.QueryRowContext(ctx, query, newS.Provider, newS.SMTPHost, newS.SMTPPort, newS.SMTPUser, newS.SMTPPass, newS.SMTPSecure, newS.SenderName, newS.SenderEmail, newS.AMQPURL).Scan(&newS.ID, &newS.UpdatedAt)
		return newS, err
	}

	// Update existing
	applyEmailSettingsUpdate(existing, req)
	query := `UPDATE email_settings SET provider=$1, smtp_host=$2, smtp_port=$3, smtp_user=$4, smtp_pass=$5, smtp_secure=$6, sender_name=$7, sender_email=$8, amqp_url=$9, updated_at=$10 WHERE id=$11`
	_, err = s.DB.ExecContext(ctx, query, existing.Provider, existing.SMTPHost, existing.SMTPPort, existing.SMTPUser, existing.SMTPPass, existing.SMTPSecure, existing.SenderName, existing.SenderEmail, existing.AMQPURL, time.Now(), existing.ID)
	if err != nil {
		return nil, err
	}
	return s.GetEmailSettings(ctx)
}

func applyEmailSettingsUpdate(s *dto.EmailSettingsDTO, req dto.UpdateEmailSettingsRequest) {
	if req.Provider != nil {
		s.Provider = *req.Provider
	}
	if req.SMTPHost != nil {
		s.SMTPHost = req.SMTPHost
	}
	if req.SMTPPort != nil {
		s.SMTPPort = req.SMTPPort
	}
	if req.SMTPUser != nil {
		s.SMTPUser = req.SMTPUser
	}
	if req.SMTPPass != nil {
		s.SMTPPass = req.SMTPPass
	}
	if req.SMTPSecure != nil {
		s.SMTPSecure = *req.SMTPSecure
	}
	if req.SenderName != nil {
		s.SenderName = *req.SenderName
	}
	if req.SenderEmail != nil {
		s.SenderEmail = *req.SenderEmail
	}
	if req.AMQPURL != nil {
		s.AMQPURL = req.AMQPURL
	}
}
