package contact

import (
	"context"
	"fmt"
	"tm/pkg/logger"
	"tm/pkg/notification"
	"tm/pkg/response"
)

// Service defines the interface for contact business operations
type Service interface {
	// Create creates a new contact message
	Create(ctx context.Context, form *CreateContactForm) (*ContactResponse, error)

	// GetByID retrieves a contact by ID
	GetByID(ctx context.Context, id string) (*ContactResponse, error)

	// Search searches contacts with filters and pagination
	Search(ctx context.Context, form *SearchContactsForm, pagination *response.Pagination) (*ContactListResponse, error)

	// UpdateStatus updates the status of a contact (admin only)
	UpdateStatus(ctx context.Context, id string, form *UpdateContactStatusForm, adminID string) error

	// GetStats returns contact statistics (admin only)
	GetStats(ctx context.Context) (*ContactStats, error)

	// Delete deletes a contact by ID (admin only)
	Delete(ctx context.Context, id string) error
}

// contactService implements Service interface
type contactService struct {
	repo   ContactRepository
	logger logger.Logger
	sdk    notification.SDK
}

// NewService creates a new contact service
func NewService(repo ContactRepository, logger logger.Logger, sdk notification.SDK) Service {
	return &contactService{
		repo:   repo,
		logger: logger,
		sdk:    sdk,
	}
}

// Create creates a new contact message
func (s *contactService) Create(ctx context.Context, form *CreateContactForm) (*ContactResponse, error) {
	s.logger.Info("Creating new contact message", map[string]interface{}{
		"email":     form.Email,
		"full_name": form.FullName,
	})

	// Create contact entity
	contact := &Contact{
		FullName: form.FullName,
		Email:    form.Email,
		Phone:    form.Phone,
		Message:  form.Message,
		Status:   ContactStatusPending,
	}

	// Save to database
	if err := s.repo.Create(ctx, contact); err != nil {
		s.logger.Error("Failed to create contact", map[string]interface{}{
			"email": form.Email,
			"error": err.Error(),
		})
		return nil, fmt.Errorf("failed to create contact: %w", err)
	}

	// Send confirmation email
	s.sdk.SendNotification(ctx, &notification.NotificationRequest{
		UserID: contact.GetID(),
		Title:  "Contact Form Submission Confirmation",
		Message: GenerateContactConfirmationEmailTemplate(&ContactEmailTemplateData{
			FullName:     contact.FullName,
			Email:        contact.Email,
			Phone:        contact.Phone,
			Message:      contact.Message,
			ContactID:    contact.GetID(),
			SubmittedAt:  contact.CreatedAt,
			CompanyName:  "Opplens",
			CompanyURL:   "https://opplens.com",
			SupportEmail: "info@opplens.com",
		}),
		Type:      "confirmation",
		Priority:  "normal",
		EventType: notification.EventTypeEmail,
		Methods: notification.NotificationMethods{
			Email: contact.Email,
		},
	})

	// Notify admin/internal team
	s.sdk.SendNotification(ctx, &notification.NotificationRequest{
		UserID: contact.GetID(),
		Title:  fmt.Sprintf("New Contact Form Submission from %s", contact.FullName),
		Message: GenerateContactConfirmationEmailTemplate(&ContactEmailTemplateData{
			FullName:     contact.FullName,
			Email:        contact.Email,
			Phone:        contact.Phone,
			Message:      contact.Message,
			ContactID:    contact.GetID(),
			SubmittedAt:  contact.CreatedAt,
			CompanyName:  "Opplens",
			CompanyURL:   "https://opplens.com",
			SupportEmail: "info@opplens.com",
		}),
		Type:      "alert",
		Priority:  "normal",
		EventType: notification.EventTypeEmail,
		Methods: notification.NotificationMethods{
			Email: "info@opplens.com",
		},
	})

	s.logger.Info("Contact message created successfully", map[string]interface{}{
		"id":    contact.GetID(),
		"email": form.Email,
	})

	return contact.ToResponse(), nil
}

// GetByID retrieves a contact by ID
func (s *contactService) GetByID(ctx context.Context, id string) (*ContactResponse, error) {
	s.logger.Debug("Retrieving contact by ID", map[string]interface{}{
		"id": id,
	})

	contact, err := s.repo.GetByID(ctx, id)
	if err != nil {
		s.logger.Error("Failed to get contact by ID", map[string]interface{}{
			"id":    id,
			"error": err.Error(),
		})
		return nil, fmt.Errorf("failed to get contact: %w", err)
	}

	return contact.ToResponse(), nil
}

// Search searches contacts with filters and pagination
func (s *contactService) Search(ctx context.Context, form *SearchContactsForm, pagination *response.Pagination) (*ContactListResponse, error) {
	s.logger.Debug("Searching contacts", map[string]interface{}{
		"filters":    form,
		"pagination": pagination,
	})

	// Validate date range if provided
	if form.DateFrom != nil && form.DateTo != nil && *form.DateFrom > *form.DateTo {
		return nil, fmt.Errorf("invalid date range: date_from must be before date_to")
	}

	result, err := s.repo.Search(ctx, *form, pagination)
	if err != nil {
		s.logger.Error("Failed to search contacts", map[string]interface{}{
			"filters": form,
			"error":   err.Error(),
		})
		return nil, fmt.Errorf("failed to search contacts: %w", err)
	}

	// Convert to response format
	contactResponses := make([]*ContactResponse, len(result.Items))
	for i, contact := range result.Items {
		contactResponses[i] = contact.ToResponse()
	}

	s.logger.Info("Contact search completed", map[string]interface{}{
		"total_count": result.TotalCount,
		"items_count": len(result.Items),
	})

	return &ContactListResponse{
		Contacts: contactResponses,
		Meta:     pagination.ListMeta(result.TotalCount, result.NextCursor, result.HasMore, result.PageOffset),
	}, nil
}

// UpdateStatus updates the status of a contact (admin only)
func (s *contactService) UpdateStatus(ctx context.Context, id string, form *UpdateContactStatusForm, adminID string) error {
	s.logger.Info("Updating contact status", map[string]interface{}{
		"id":       id,
		"status":   form.Status,
		"admin_id": adminID,
	})

	// Validate status transition
	contact, err := s.repo.GetByID(ctx, id)
	if err != nil {
		s.logger.Error("Failed to get contact for status update", map[string]interface{}{
			"id":    id,
			"error": err.Error(),
		})
		return fmt.Errorf("failed to get contact: %w", err)
	}

	// Check if contact can be updated
	if !contact.CanBeUpdated() {
		s.logger.Warn("Attempted to update closed contact", map[string]interface{}{
			"id":             id,
			"current_status": contact.Status,
			"new_status":     form.Status,
		})
		return fmt.Errorf("contact is closed and cannot be updated")
	}

	// Update status
	status := ContactStatus(form.Status)
	err = s.repo.UpdateStatus(ctx, id, status, form.AdminNotes, &adminID)
	if err != nil {
		s.logger.Error("Failed to update contact status", map[string]interface{}{
			"id":     id,
			"status": form.Status,
			"error":  err.Error(),
		})
		return fmt.Errorf("failed to update contact status: %w", err)
	}

	s.logger.Info("Contact status updated successfully", map[string]interface{}{
		"id":       id,
		"status":   form.Status,
		"admin_id": adminID,
	})

	return nil
}

// GetStats returns contact statistics (admin only)
func (s *contactService) GetStats(ctx context.Context) (*ContactStats, error) {
	s.logger.Debug("Getting contact statistics", nil)

	stats, err := s.repo.GetStats(ctx)
	if err != nil {
		s.logger.Error("Failed to get contact stats", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, fmt.Errorf("failed to get contact stats: %w", err)
	}

	s.logger.Info("Contact statistics retrieved", map[string]interface{}{
		"total":       stats.Total,
		"pending":     stats.Pending,
		"in_progress": stats.InProgress,
		"resolved":    stats.Resolved,
		"closed":      stats.Closed,
	})

	return stats, nil
}

// Delete deletes a contact by ID (admin only)
func (s *contactService) Delete(ctx context.Context, id string) error {
	s.logger.Info("Deleting contact", map[string]interface{}{
		"id": id,
	})

	// Check if contact exists
	contact, err := s.repo.GetByID(ctx, id)
	if err != nil {
		s.logger.Error("Failed to get contact for deletion", map[string]interface{}{
			"id":    id,
			"error": err.Error(),
		})
		return fmt.Errorf("failed to get contact: %w", err)
	}

	// Delete the contact
	if err := s.repo.Delete(ctx, id); err != nil {
		s.logger.Error("Failed to delete contact", map[string]interface{}{
			"id":    id,
			"error": err.Error(),
		})
		return fmt.Errorf("failed to delete contact: %w", err)
	}

	s.logger.Info("Contact deleted successfully", map[string]interface{}{
		"id":    id,
		"email": contact.Email,
	})

	return nil
}
