package services

import (
	"context"
	"fmt"
	"time"

	"github.com/breakpilot/consent-service/internal/models"
	"github.com/google/uuid"
	"github.com/jackc/pgx/v5/pgxpool"
)

// EmailTemplateService handles email template management
type EmailTemplateService struct {
	db *pgxpool.Pool
}

// NewEmailTemplateService creates a new email template service
func NewEmailTemplateService(db *pgxpool.Pool) *EmailTemplateService {
	return &EmailTemplateService{db: db}
}

// CreateEmailTemplate creates a new email template type
func (s *EmailTemplateService) CreateEmailTemplate(ctx context.Context, req *models.CreateEmailTemplateRequest) (*models.EmailTemplate, error) {
	template := &models.EmailTemplate{
		ID:          uuid.New(),
		Type:        req.Type,
		Name:        req.Name,
		Description: req.Description,
		IsActive:    true,
		SortOrder:   0,
		CreatedAt:   time.Now(),
		UpdatedAt:   time.Now(),
	}

	_, err := s.db.Exec(ctx, `
		INSERT INTO email_templates (id, type, name, description, is_active, sort_order, created_at, updated_at)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
	`, template.ID, template.Type, template.Name, template.Description, template.IsActive, template.SortOrder, template.CreatedAt, template.UpdatedAt)

	if err != nil {
		return nil, fmt.Errorf("failed to create email template: %w", err)
	}

	return template, nil
}

// GetAllTemplates returns all email templates with their latest published versions
func (s *EmailTemplateService) GetAllTemplates(ctx context.Context) ([]models.EmailTemplateWithVersion, error) {
	rows, err := s.db.Query(ctx, `
		SELECT
			t.id, t.type, t.name, t.description, t.is_active, t.sort_order, t.created_at, t.updated_at,
			v.id, v.template_id, v.version, v.language, v.subject, v.body_html, v.body_text,
			v.summary, v.status, v.published_at, v.scheduled_publish_at, v.created_by,
			v.approved_by, v.approved_at, v.created_at, v.updated_at
		FROM email_templates t
		LEFT JOIN email_template_versions v ON t.id = v.template_id AND v.status = 'published'
		ORDER BY t.sort_order, t.name
	`)
	if err != nil {
		return nil, fmt.Errorf("failed to get email templates: %w", err)
	}
	defer rows.Close()

	var results []models.EmailTemplateWithVersion
	for rows.Next() {
		var template models.EmailTemplate
		var versionID, templateID, createdBy, approvedBy *uuid.UUID
		var publishedAt, scheduledPublishAt, approvedAt, vCreatedAt, vUpdatedAt *time.Time
		var vVersion, vLanguage, vSubject, vBodyHTML, vBodyText, vSummary, vStatus *string

		err := rows.Scan(
			&template.ID, &template.Type, &template.Name, &template.Description,
			&template.IsActive, &template.SortOrder, &template.CreatedAt, &template.UpdatedAt,
			&versionID, &templateID, &vVersion, &vLanguage, &vSubject, &vBodyHTML, &vBodyText,
			&vSummary, &vStatus, &publishedAt, &scheduledPublishAt, &createdBy,
			&approvedBy, &approvedAt, &vCreatedAt, &vUpdatedAt,
		)
		if err != nil {
			return nil, fmt.Errorf("failed to scan email template: %w", err)
		}

		result := models.EmailTemplateWithVersion{Template: template}
		if versionID != nil {
			result.LatestVersion = &models.EmailTemplateVersion{
				ID:                 *versionID,
				TemplateID:         *templateID,
				Version:            *vVersion,
				Language:           *vLanguage,
				Subject:            *vSubject,
				BodyHTML:           *vBodyHTML,
				BodyText:           *vBodyText,
				Status:             *vStatus,
				PublishedAt:        publishedAt,
				ScheduledPublishAt: scheduledPublishAt,
				CreatedBy:          createdBy,
				ApprovedBy:         approvedBy,
				ApprovedAt:         approvedAt,
			}
			if vSummary != nil {
				result.LatestVersion.Summary = vSummary
			}
			if vCreatedAt != nil {
				result.LatestVersion.CreatedAt = *vCreatedAt
			}
			if vUpdatedAt != nil {
				result.LatestVersion.UpdatedAt = *vUpdatedAt
			}
		}
		results = append(results, result)
	}

	return results, nil
}

// GetTemplateByID returns a template by ID
func (s *EmailTemplateService) GetTemplateByID(ctx context.Context, id uuid.UUID) (*models.EmailTemplate, error) {
	var template models.EmailTemplate
	err := s.db.QueryRow(ctx, `
		SELECT id, type, name, description, is_active, sort_order, created_at, updated_at
		FROM email_templates WHERE id = $1
	`, id).Scan(&template.ID, &template.Type, &template.Name, &template.Description,
		&template.IsActive, &template.SortOrder, &template.CreatedAt, &template.UpdatedAt)
	if err != nil {
		return nil, fmt.Errorf("failed to get email template: %w", err)
	}
	return &template, nil
}

// GetTemplateByType returns a template by type
func (s *EmailTemplateService) GetTemplateByType(ctx context.Context, templateType string) (*models.EmailTemplate, error) {
	var template models.EmailTemplate
	err := s.db.QueryRow(ctx, `
		SELECT id, type, name, description, is_active, sort_order, created_at, updated_at
		FROM email_templates WHERE type = $1
	`, templateType).Scan(&template.ID, &template.Type, &template.Name, &template.Description,
		&template.IsActive, &template.SortOrder, &template.CreatedAt, &template.UpdatedAt)
	if err != nil {
		return nil, fmt.Errorf("failed to get email template: %w", err)
	}
	return &template, nil
}

// CreateTemplateVersion creates a new version of an email template
func (s *EmailTemplateService) CreateTemplateVersion(ctx context.Context, req *models.CreateEmailTemplateVersionRequest, createdBy uuid.UUID) (*models.EmailTemplateVersion, error) {
	templateID, err := uuid.Parse(req.TemplateID)
	if err != nil {
		return nil, fmt.Errorf("invalid template ID: %w", err)
	}

	version := &models.EmailTemplateVersion{
		ID:         uuid.New(),
		TemplateID: templateID,
		Version:    req.Version,
		Language:   req.Language,
		Subject:    req.Subject,
		BodyHTML:   req.BodyHTML,
		BodyText:   req.BodyText,
		Summary:    req.Summary,
		Status:     "draft",
		CreatedBy:  &createdBy,
		CreatedAt:  time.Now(),
		UpdatedAt:  time.Now(),
	}

	_, err = s.db.Exec(ctx, `
		INSERT INTO email_template_versions
		(id, template_id, version, language, subject, body_html, body_text, summary, status, created_by, created_at, updated_at)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
	`, version.ID, version.TemplateID, version.Version, version.Language, version.Subject,
	   version.BodyHTML, version.BodyText, version.Summary, version.Status, version.CreatedBy,
	   version.CreatedAt, version.UpdatedAt)

	if err != nil {
		return nil, fmt.Errorf("failed to create email template version: %w", err)
	}

	return version, nil
}

// GetVersionsByTemplateID returns all versions for a template
func (s *EmailTemplateService) GetVersionsByTemplateID(ctx context.Context, templateID uuid.UUID) ([]models.EmailTemplateVersion, error) {
	rows, err := s.db.Query(ctx, `
		SELECT id, template_id, version, language, subject, body_html, body_text, summary, status,
		       published_at, scheduled_publish_at, created_by, approved_by, approved_at, created_at, updated_at
		FROM email_template_versions
		WHERE template_id = $1
		ORDER BY created_at DESC
	`, templateID)
	if err != nil {
		return nil, fmt.Errorf("failed to get template versions: %w", err)
	}
	defer rows.Close()

	var versions []models.EmailTemplateVersion
	for rows.Next() {
		var v models.EmailTemplateVersion
		err := rows.Scan(&v.ID, &v.TemplateID, &v.Version, &v.Language, &v.Subject, &v.BodyHTML, &v.BodyText,
			&v.Summary, &v.Status, &v.PublishedAt, &v.ScheduledPublishAt, &v.CreatedBy, &v.ApprovedBy,
			&v.ApprovedAt, &v.CreatedAt, &v.UpdatedAt)
		if err != nil {
			return nil, fmt.Errorf("failed to scan template version: %w", err)
		}
		versions = append(versions, v)
	}

	return versions, nil
}

// GetVersionByID returns a version by ID
func (s *EmailTemplateService) GetVersionByID(ctx context.Context, id uuid.UUID) (*models.EmailTemplateVersion, error) {
	var v models.EmailTemplateVersion
	err := s.db.QueryRow(ctx, `
		SELECT id, template_id, version, language, subject, body_html, body_text, summary, status,
		       published_at, scheduled_publish_at, created_by, approved_by, approved_at, created_at, updated_at
		FROM email_template_versions WHERE id = $1
	`, id).Scan(&v.ID, &v.TemplateID, &v.Version, &v.Language, &v.Subject, &v.BodyHTML, &v.BodyText,
		&v.Summary, &v.Status, &v.PublishedAt, &v.ScheduledPublishAt, &v.CreatedBy, &v.ApprovedBy,
		&v.ApprovedAt, &v.CreatedAt, &v.UpdatedAt)
	if err != nil {
		return nil, fmt.Errorf("failed to get template version: %w", err)
	}
	return &v, nil
}

// GetPublishedVersion returns the published version for a template and language
func (s *EmailTemplateService) GetPublishedVersion(ctx context.Context, templateType, language string) (*models.EmailTemplateVersion, error) {
	var v models.EmailTemplateVersion
	err := s.db.QueryRow(ctx, `
		SELECT v.id, v.template_id, v.version, v.language, v.subject, v.body_html, v.body_text,
		       v.summary, v.status, v.published_at, v.scheduled_publish_at, v.created_by,
		       v.approved_by, v.approved_at, v.created_at, v.updated_at
		FROM email_template_versions v
		JOIN email_templates t ON t.id = v.template_id
		WHERE t.type = $1 AND v.language = $2 AND v.status = 'published'
		ORDER BY v.published_at DESC
		LIMIT 1
	`, templateType, language).Scan(&v.ID, &v.TemplateID, &v.Version, &v.Language, &v.Subject, &v.BodyHTML, &v.BodyText,
		&v.Summary, &v.Status, &v.PublishedAt, &v.ScheduledPublishAt, &v.CreatedBy, &v.ApprovedBy,
		&v.ApprovedAt, &v.CreatedAt, &v.UpdatedAt)
	if err != nil {
		return nil, fmt.Errorf("failed to get published version: %w", err)
	}
	return &v, nil
}

// UpdateVersion updates a version
func (s *EmailTemplateService) UpdateVersion(ctx context.Context, id uuid.UUID, req *models.UpdateEmailTemplateVersionRequest) error {
	query := "UPDATE email_template_versions SET updated_at = $1"
	args := []interface{}{time.Now()}
	argIdx := 2

	if req.Subject != nil {
		query += fmt.Sprintf(", subject = $%d", argIdx)
		args = append(args, *req.Subject)
		argIdx++
	}
	if req.BodyHTML != nil {
		query += fmt.Sprintf(", body_html = $%d", argIdx)
		args = append(args, *req.BodyHTML)
		argIdx++
	}
	if req.BodyText != nil {
		query += fmt.Sprintf(", body_text = $%d", argIdx)
		args = append(args, *req.BodyText)
		argIdx++
	}
	if req.Summary != nil {
		query += fmt.Sprintf(", summary = $%d", argIdx)
		args = append(args, *req.Summary)
		argIdx++
	}
	if req.Status != nil {
		query += fmt.Sprintf(", status = $%d", argIdx)
		args = append(args, *req.Status)
		argIdx++
	}

	query += fmt.Sprintf(" WHERE id = $%d", argIdx)
	args = append(args, id)

	_, err := s.db.Exec(ctx, query, args...)
	if err != nil {
		return fmt.Errorf("failed to update version: %w", err)
	}
	return nil
}
