package inquiry

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

// Service defines business logic for inquiry operations
type Service interface {
	Create(ctx context.Context, form *CreateInquiryForm) (*InquiryResponse, error)
	GetByID(ctx context.Context, id string) (*InquiryResponse, error)
	UpdateStatus(ctx context.Context, id string, form *UpdateInquiryStatusForm, changedBy string) (*InquiryResponse, error)
	Search(ctx context.Context, form *SearchInquiriesForm, pagination *response.Pagination) (*InquiryListResponse, error)
	Delete(ctx context.Context, id string) error
}

// inquiryService implements the Service interface
type inquiryService struct {
	repository Repository
	sdk        notification.SDK
	logger     logger.Logger
	xssPolicy  *security.XSSPolicy
}

// NewService creates a new inquiry service
func NewService(repository Repository, sdk notification.SDK, logger logger.Logger, xssPolicy *security.XSSPolicy) Service {
	return &inquiryService{
		repository: repository,
		sdk:        sdk,
		logger:     logger,
		xssPolicy:  xssPolicy,
	}
}

// Create creates a new inquiry
func (s *inquiryService) Create(ctx context.Context, form *CreateInquiryForm) (*InquiryResponse, error) {
	s.logger.Info("Creating new inquiry", map[string]interface{}{
		"work_email":   form.WorkEmail,
		"company_name": form.CompanyName,
		"full_name":    form.FullName,
	})

	// Check for duplicate pending inquiries by email
	existingInquiry, err := s.repository.CheckPendingInquiry(ctx, form.WorkEmail)
	if err != nil {
		s.logger.Error("Failed to check for duplicate inquiry by email", map[string]interface{}{
			"error":      err.Error(),
			"work_email": form.WorkEmail,
		})
		return nil, errors.New("failed to validate inquiry")
	}

	if existingInquiry != nil {
		s.logger.Warn("Duplicate inquiry attempt by email", map[string]interface{}{
			"work_email":      form.WorkEmail,
			"existing_id":     existingInquiry.ID,
			"existing_status": existingInquiry.Status,
			"created_at":      existingInquiry.CreatedAt,
		})
		return nil, NewDuplicateInquiryError("email", existingInquiry.ID.Hex(), existingInquiry.Status, existingInquiry.CreatedAt)
	}

	// Check for duplicate pending inquiries by phone number
	existingInquiryByPhone, err := s.repository.CheckPendingInquiryByPhone(ctx, form.PhoneNumber)
	if err != nil {
		s.logger.Error("Failed to check for duplicate inquiry by phone", map[string]interface{}{
			"error":        err.Error(),
			"phone_number": form.PhoneNumber,
		})
		return nil, errors.New("failed to validate inquiry")
	}

	if existingInquiryByPhone != nil {
		s.logger.Warn("Duplicate inquiry attempt by phone", map[string]interface{}{
			"phone_number":    form.PhoneNumber,
			"existing_id":     existingInquiryByPhone.ID,
			"existing_status": existingInquiryByPhone.Status,
			"created_at":      existingInquiryByPhone.CreatedAt,
		})
		return nil, NewDuplicateInquiryError("phone", existingInquiryByPhone.ID.Hex(), existingInquiryByPhone.Status, existingInquiryByPhone.CreatedAt)
	}

	// Create inquiry entity
	inquiry := &Inquiry{
		FullName:    form.FullName,
		CompanyName: form.CompanyName,
		WorkEmail:   form.WorkEmail,
		PhoneNumber: form.PhoneNumber,
	}

	// Save to database
	err = s.repository.Create(ctx, inquiry)
	if err != nil {
		s.logger.Error("Failed to create inquiry", map[string]interface{}{
			"error":        err.Error(),
			"work_email":   form.WorkEmail,
			"company_name": form.CompanyName,
		})
		return nil, errors.New("failed to create inquiry")
	}

	s.sdk.SendNotification(ctx, &notification.NotificationRequest{
		UserID: inquiry.ID.Hex(),
		Title:  fmt.Sprintf("New Inquiry from %s", inquiry.CompanyName),
		Message: GenerateNewInquiryEmailTemplate(&EmailTemplateData{
			FullName:     inquiry.FullName,
			CompanyName:  inquiry.CompanyName,
			WorkEmail:    inquiry.WorkEmail,
			PhoneNumber:  inquiry.PhoneNumber,
			InquiryID:    inquiry.ID.Hex(),
			CreatedAt:    inquiry.CreatedAt,
			CompanyLogo:  "",
			CompanyURL:   "https://opplens.com",
			SupportEmail: "info@opplens.com",
		}, s.xssPolicy),
		Type:      "alert",
		Priority:  "important",
		EventType: notification.EventTypeEmail,
		Methods: notification.NotificationMethods{
			Email: "info@opplens.com",
		},
	})

	// TODO: Should be removed only for testing
	s.sdk.SendNotification(ctx, &notification.NotificationRequest{
		UserID: inquiry.ID.Hex(),
		Title:  fmt.Sprintf("New Inquiry from %s", inquiry.CompanyName),
		Message: GenerateNewInquiryEmailTemplate(&EmailTemplateData{
			FullName:     inquiry.FullName,
			CompanyName:  inquiry.CompanyName,
			WorkEmail:    inquiry.WorkEmail,
			PhoneNumber:  inquiry.PhoneNumber,
			InquiryID:    inquiry.ID.Hex(),
			CreatedAt:    inquiry.CreatedAt,
			CompanyLogo:  "",
			CompanyURL:   "https://opplens.com",
			SupportEmail: "info@opplens.com",
		}, s.xssPolicy),
		Type:      "alert",
		Priority:  "important",
		EventType: notification.EventTypeEmail,
		Methods: notification.NotificationMethods{
			Email: "nakhostin.nima1998@gmail.com",
		},
	})

	s.logger.Info("Inquiry created successfully", map[string]interface{}{
		"inquiry_id":   inquiry.ID,
		"work_email":   inquiry.WorkEmail,
		"company_name": inquiry.CompanyName,
		"status":       inquiry.Status,
	})

	return inquiry.ToResponse(), nil
}

// GetByID retrieves an inquiry by ID
func (s *inquiryService) GetByID(ctx context.Context, id string) (*InquiryResponse, error) {
	s.logger.Info("Getting inquiry by ID", map[string]interface{}{
		"inquiry_id": id,
	})

	inquiry, err := s.repository.GetByID(ctx, id)
	if err != nil {
		s.logger.Error("Failed to get inquiry by ID", map[string]interface{}{
			"error":      err.Error(),
			"inquiry_id": id,
		})
		return nil, err
	}

	s.logger.Info("Inquiry retrieved successfully", map[string]interface{}{
		"inquiry_id": id,
		"status":     inquiry.Status,
	})

	return inquiry.ToResponse(), nil
}

// UpdateStatus updates the status of an inquiry
func (s *inquiryService) UpdateStatus(ctx context.Context, id string, form *UpdateInquiryStatusForm, changedBy string) (*InquiryResponse, error) {
	s.logger.Info("Updating inquiry status", map[string]interface{}{
		"inquiry_id": id,
		"new_status": form.Status,
		"changed_by": changedBy,
	})

	// Validate status transition
	err := s.validateStatusTransition(ctx, id, form.Status)
	if err != nil {
		s.logger.Error("Invalid status transition", map[string]interface{}{
			"error":      err.Error(),
			"inquiry_id": id,
			"new_status": form.Status,
		})
		return nil, err
	}

	// Update status in repository
	err = s.repository.UpdateStatus(ctx, id, form.Status, form.Reason, changedBy, form.Description)
	if err != nil {
		s.logger.Error("Failed to update inquiry status", map[string]interface{}{
			"error":      err.Error(),
			"inquiry_id": id,
			"new_status": form.Status,
		})
		return nil, errors.New("failed to update inquiry status")
	}

	// Get updated inquiry
	inquiry, err := s.repository.GetByID(ctx, id)
	if err != nil {
		s.logger.Error("Failed to get updated inquiry", map[string]interface{}{
			"error":      err.Error(),
			"inquiry_id": id,
		})
		return nil, err
	}

	s.logger.Info("Inquiry status updated successfully", map[string]interface{}{
		"inquiry_id": id,
		"new_status": form.Status,
		"changed_by": changedBy,
	})

	return inquiry.ToResponse(), nil
}

// validateStatusTransition validates if the status transition is allowed
func (s *inquiryService) validateStatusTransition(ctx context.Context, id string, newStatus string) error {
	// Get current inquiry
	inquiry, err := s.repository.GetByID(ctx, id)
	if err != nil {
		return err
	}

	currentStatus := inquiry.GetCurrentStatus()

	// Define allowed transitions
	allowedTransitions := map[string][]string{
		StatusPending:  {StatusReviewed, StatusRejected},
		StatusReviewed: {StatusApproved, StatusRejected},
		StatusApproved: {}, // No transitions from approved
		StatusRejected: {}, // No transitions from rejected
	}

	allowedNextStatuses, exists := allowedTransitions[currentStatus]
	if !exists {
		return errors.New("invalid current status")
	}

	// Check if transition is allowed
	for _, allowedStatus := range allowedNextStatuses {
		if allowedStatus == newStatus {
			return nil
		}
	}

	return errors.New("invalid status transition: cannot change from " + currentStatus + " to " + newStatus)
}

// Search searches inquiries with search and filters
func (s *inquiryService) Search(ctx context.Context, form *SearchInquiriesForm, pagination *response.Pagination) (*InquiryListResponse, error) {
	s.logger.Info("Searching inquiries", map[string]interface{}{
		"search": form.Search,
		"status": form.Status,
		"limit":  pagination.Limit,
		"offset": pagination.Offset,
	})

	page, err := s.repository.Search(ctx, form, pagination)
	if err != nil {
		s.logger.Error("Failed to search inquiries", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, err
	}

	var inquiryResponses []*InquiryResponse
	for _, inquiry := range page.Items {
		inquiryResponses = append(inquiryResponses, inquiry.ToResponse())
	}

	s.logger.Info("Inquiries search completed successfully", map[string]interface{}{
		"total_found": page.TotalCount,
		"returned":    len(inquiryResponses),
	})

	return &InquiryListResponse{
		Inquiries: inquiryResponses,
		Meta:      pagination.ListMeta(page.TotalCount, page.NextCursor, page.HasMore, page.PageOffset),
	}, nil
}

// Delete deletes an inquiry
func (s *inquiryService) Delete(ctx context.Context, id string) error {
	s.logger.Info("Deleting inquiry", map[string]interface{}{
		"inquiry_id": id,
	})

	err := s.repository.Delete(ctx, id)
	if err != nil {
		s.logger.Error("Failed to delete inquiry", map[string]interface{}{
			"error":      err.Error(),
			"inquiry_id": id,
		})
		return err
	}

	s.logger.Info("Inquiry deleted successfully", map[string]interface{}{
		"inquiry_id": id,
	})

	return nil
}
