package cms

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

// Service defines the interface for CMS business operations
type Service interface {
	// Create creates a new CMS entry
	Create(ctx context.Context, form *CMSForm) (*CMSResponse, error)

	// GetByID retrieves a CMS entry by ID
	GetByID(ctx context.Context, id string) (*CMSResponse, error)

	// GetByKey retrieves a CMS entry by key
	GetByKey(ctx context.Context, key string) (*CMSResponse, error)

	// Update updates a CMS entry
	Update(ctx context.Context, id string, form *CMSForm) (*CMSResponse, error)

	// Delete deletes a CMS entry by ID
	Delete(ctx context.Context, id string) error

	// Search searches CMS entries with filters and pagination
	Search(ctx context.Context, form *SearchCMSForm, pagination *response.Pagination) (*CMSListResponse, error)
}

// cmsService implements Service interface
type cmsService struct {
	repo   Repository
	logger logger.Logger
}

// NewService creates a new CMS service
func NewService(repo Repository, logger logger.Logger) Service {
	return &cmsService{
		repo:   repo,
		logger: logger,
	}
}

// Create creates a new CMS entry
func (s *cmsService) Create(ctx context.Context, form *CMSForm) (*CMSResponse, error) {
	s.logger.Info("Creating new CMS entry", map[string]interface{}{
		"key": form.Key,
	})

	// Check if CMS with this key already exists
	existing, err := s.repo.GetByKey(ctx, form.Key)
	if err == nil && existing != nil {
		s.logger.Warn("CMS with this key already exists", map[string]interface{}{
			"key": form.Key,
		})
		return nil, ErrCMSKeyExists
	}

	// Create CMS entity
	cms := &CMS{
		Key: form.Key,
	}

	// Copy form data to entity
	s.copyFormToEntity(form, cms)

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

	s.logger.Info("CMS entry created successfully", map[string]interface{}{
		"id":  cms.GetID(),
		"key": form.Key,
	})

	return cms.ToResponse(), nil
}

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

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

	return cms.ToResponse(), nil
}

// GetByKey retrieves a CMS entry by key
func (s *cmsService) GetByKey(ctx context.Context, key string) (*CMSResponse, error) {
	s.logger.Debug("Retrieving CMS by key", map[string]interface{}{
		"key": key,
	})

	cms, err := s.repo.GetByKey(ctx, key)
	if err != nil {
		if errors.Is(err, ErrCMSNotFound) {
			return nil, ErrCMSNotFound
		}
		s.logger.Error("Failed to get CMS by key", map[string]interface{}{
			"key":   key,
			"error": err.Error(),
		})
		return nil, fmt.Errorf("failed to get CMS: %w", err)
	}

	return cms.ToResponse(), nil
}

// Update updates a CMS entry
func (s *cmsService) Update(ctx context.Context, id string, form *CMSForm) (*CMSResponse, error) {
	s.logger.Info("Updating CMS entry", map[string]interface{}{
		"id":  id,
		"key": form.Key,
	})

	// Get existing CMS
	cms, err := s.repo.GetByID(ctx, id)
	if err != nil {
		if errors.Is(err, ErrCMSNotFound) {
			return nil, ErrCMSNotFound
		}
		s.logger.Error("Failed to get existing CMS for update", map[string]interface{}{
			"id":    id,
			"error": err.Error(),
		})
		return nil, fmt.Errorf("failed to get CMS for update: %w", err)
	}

	// Check if key is being changed and if new key already exists
	if cms.Key != form.Key {
		existing, err := s.repo.GetByKey(ctx, form.Key)
		if err == nil && existing != nil && existing.GetID() != id {
			s.logger.Warn("CMS with this key already exists", map[string]interface{}{
				"key": form.Key,
			})
			return nil, ErrCMSKeyExists
		}
		cms.Key = form.Key
	}

	// Copy form data to entity
	s.copyFormToEntity(form, cms)

	// Update in database
	if err := s.repo.Update(ctx, cms); err != nil {
		s.logger.Error("Failed to update CMS", map[string]interface{}{
			"id":    id,
			"key":   form.Key,
			"error": err.Error(),
		})
		return nil, fmt.Errorf("failed to update CMS: %w", err)
	}

	s.logger.Info("CMS entry updated successfully", map[string]interface{}{
		"id":  id,
		"key": form.Key,
	})

	return cms.ToResponse(), nil
}

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

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

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

	return nil
}

// Search searches CMS entries with filters and pagination
func (s *cmsService) Search(ctx context.Context, form *SearchCMSForm, pagination *response.Pagination) (*CMSListResponse, error) {
	s.logger.Debug("Searching CMS entries", map[string]interface{}{
		"filters":    form,
		"pagination": pagination,
	})

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

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

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

	return &CMSListResponse{
		CMS:  cmsResponses,
		Meta: pagination.ListMeta(result.TotalCount, result.NextCursor, result.HasMore, result.PageOffset),
	}, nil
}

// copyFormToEntity copies data from form to entity
func (s *cmsService) copyFormToEntity(form *CMSForm, cms *CMS) {
	if form.Type != "" {
		cms.Type = CMSType(form.Type)
	}

	switch cms.Type {
	case CMSTypeCompany:
		if form.Language != "" {
			cms.Language = form.Language
		}
		if form.CompanyName != "" {
			cms.CompanyName = form.CompanyName
		}
		if form.Country != "" {
			cms.Country = form.Country
		}
	case CMSTypeOrganization:
		cms.Language = ""
		cms.CompanyName = ""
		cms.Country = ""
	}

	// Hero section
	if form.Hero.Title != "" {
		cms.Hero.Title = form.Hero.Title
	}
	if form.Hero.Description != "" {
		cms.Hero.Description = form.Hero.Description
	}
	if form.Hero.ButtonText != "" {
		cms.Hero.ButtonText = form.Hero.ButtonText
	}
	if form.Hero.ButtonLink != "" {
		cms.Hero.ButtonLink = form.Hero.ButtonLink
	}
	if form.Hero.GifFile != "" {
		cms.Hero.GifFile = form.Hero.GifFile
	}

	// Chart section
	if form.Chart.Title != "" {
		cms.Chart.Title = form.Chart.Title
	}
	if form.Chart.MissedAmount != "" {
		cms.Chart.MissedAmount = form.Chart.MissedAmount
	}
	if len(form.Chart.Data) > 0 {
		cms.Chart.Data = make([]chartPoint, len(form.Chart.Data))
		for i, point := range form.Chart.Data {
			cms.Chart.Data[i] = chartPoint(point)
		}
	}

	// Features section
	s.copyCardSectionForm(&form.Features, &cms.Features)

	// Challenges section
	s.copyCardSectionForm(&form.Challenges, &cms.Challenges)

	// Advantages section
	s.copyCardSectionForm(&form.Advantages, &cms.Advantages)

	// Contact section
	if form.Contact.Title != "" {
		cms.Contact.Title = form.Contact.Title
	}
	if form.Contact.Description != "" {
		cms.Contact.Description = form.Contact.Description
	}
	if form.Contact.SubmitButtonText != "" {
		cms.Contact.SubmitButtonText = form.Contact.SubmitButtonText
	}
	if len(form.Contact.Fields) > 0 {
		cms.Contact.Fields = make([]formField, len(form.Contact.Fields))
		for i, field := range form.Contact.Fields {
			cms.Contact.Fields[i] = formField{
				Name:        field.Name,
				Label:       field.Label,
				Placeholder: field.Placeholder,
				Required:    field.Required,
			}
		}
	}

	// Footer section
	if form.Footer.Email != "" {
		cms.Footer.Email = form.Footer.Email
	}
	if form.Footer.Phone != "" {
		cms.Footer.Phone = form.Footer.Phone
	}
	if form.Footer.Location != "" {
		cms.Footer.Location = form.Footer.Location
	}
	if form.Footer.Tagline != "" {
		cms.Footer.Tagline = form.Footer.Tagline
	}
	if form.Footer.Copyright != "" {
		cms.Footer.Copyright = form.Footer.Copyright
	}
}

// copyCardSectionForm copies card section form data to entity
func (s *cmsService) copyCardSectionForm(formSection *cardSectionForm, entitySection *cardSection) {
	if formSection.Title != "" {
		entitySection.Title = formSection.Title
	}
	if formSection.Description != "" {
		entitySection.Description = formSection.Description
	}
	if len(formSection.Cards) > 0 {
		entitySection.Cards = make([]card, len(formSection.Cards))
		for i, cardForm := range formSection.Cards {
			entitySection.Cards[i] = card{
				Icon:        cardForm.Icon,
				Title:       cardForm.Title,
				Description: cardForm.Description,
			}
		}
	}
}
