package company_category

import (
	"context"
	"errors"

	"tm/pkg/logger"
	"tm/pkg/response"
)

// Service defines business logic for category operations
type Service interface {
	// Core category operations
	Create(ctx context.Context, form *CategoryForm) (*CategoryResponse, error)
	Update(ctx context.Context, id string, form *CategoryForm) (*CategoryResponse, error)
	GetByID(ctx context.Context, id string) (*CategoryResponse, error)
	GetByIDs(ctx context.Context, ids []string) ([]*CategoryResponse, error)
	Delete(ctx context.Context, id string) error

	// Category listing and search
	SearchCategories(ctx context.Context, form *SearchForm, pagination *response.Pagination) (*CategoryListResponse, error)

	// Category management
	TogglePublish(ctx context.Context, id string) (bool, error)
}

// categoryService implements the Service interface
type categoryService struct {
	repository Repository
	logger     logger.Logger
}

// NewCategoryService creates a new category service
func NewCategoryService(repository Repository, logger logger.Logger) Service {
	return &categoryService{
		repository: repository,
		logger:     logger,
	}
}

// Create creates a new category
func (s *categoryService) Create(ctx context.Context, form *CategoryForm) (*CategoryResponse, error) {
	// Check if category name already exists
	existingCategory, _ := s.repository.GetByName(ctx, form.Name)
	if existingCategory != nil {
		return nil, errors.New("category with this name already exists")
	}

	// Create category
	category := &Category{
		Name:        form.Name,
		Description: form.Description,
		Thumbnail:   form.Thumbnail,
		Published:   false, // Default to unpublished
	}

	// Save to database
	err := s.repository.Create(ctx, category)
	if err != nil {
		s.logger.Error("Failed to create category", map[string]interface{}{
			"error": err.Error(),
			"name":  form.Name,
		})
		return nil, err
	}

	s.logger.Info("Category created successfully", map[string]interface{}{
		"category_id": category.ID,
		"name":        category.Name,
		"published":   category.Published,
	})

	return category.ToResponse(), nil
}

// GetByIDs retrieves categories by IDs
func (s *categoryService) GetByIDs(ctx context.Context, ids []string) ([]*CategoryResponse, error) {
	categories, err := s.repository.GetByIDs(ctx, ids)
	if err != nil {
		return nil, err
	}

	var categoryResponses []*CategoryResponse
	for _, category := range categories {
		categoryResponses = append(categoryResponses, category.ToResponse())
	}

	return categoryResponses, nil
}

// GetByID retrieves a category by ID
func (s *categoryService) GetByID(ctx context.Context, id string) (*CategoryResponse, error) {
	category, err := s.repository.GetByID(ctx, id)
	if err != nil {
		s.logger.Error("Failed to get category by ID", map[string]interface{}{
			"error":       err.Error(),
			"category_id": id,
		})
		return nil, err
	}

	s.logger.Info("Category retrieved successfully", map[string]interface{}{
		"category_id": category.ID,
		"name":        category.Name,
	})

	return category.ToResponse(), nil
}

// Update updates a category
func (s *categoryService) Update(ctx context.Context, id string, form *CategoryForm) (*CategoryResponse, error) {
	// Get existing category
	category, err := s.repository.GetByID(ctx, id)
	if err != nil {
		s.logger.Error("Failed to get category for update", map[string]interface{}{
			"error":       err.Error(),
			"category_id": id,
		})
		return nil, errors.New("category not found")
	}

	// Check if name already exists (if changing name)
	if form.Name != "" && form.Name != category.Name {
		existingCategory, _ := s.repository.GetByName(ctx, form.Name)
		if existingCategory != nil {
			return nil, errors.New("category with this name already exists")
		}
		category.Name = form.Name
	}

	// Update fields if provided
	if form.Description != nil {
		category.Description = form.Description
	}

	if form.Thumbnail != nil {
		category.Thumbnail = form.Thumbnail
	}

	// Update in database
	err = s.repository.Update(ctx, category)
	if err != nil {
		s.logger.Error("Failed to update category", map[string]interface{}{
			"error":       err.Error(),
			"category_id": id,
		})
		return nil, errors.New("failed to update category")
	}

	s.logger.Info("Category updated successfully", map[string]interface{}{
		"category_id": category.ID,
		"name":        category.Name,
	})

	return category.ToResponse(), nil
}

// Delete deletes a category
func (s *categoryService) Delete(ctx context.Context, id string) error {
	// Delete category
	err := s.repository.Delete(ctx, id)
	if err != nil {
		s.logger.Error("Failed to delete category", map[string]interface{}{
			"error":       err.Error(),
			"category_id": id,
		})
		return errors.New("failed to delete category")
	}

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

	return nil
}

// SearchCategories searches categories with filters
func (s *categoryService) SearchCategories(ctx context.Context, form *SearchForm, pagination *response.Pagination) (*CategoryListResponse, error) {
	// Get categories using search
	categories, total, err := s.repository.Search(ctx, form, pagination)
	if err != nil {
		s.logger.Error("Failed to search categories", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, errors.New("failed to search categories")
	}

	// Convert to responses
	var categoryResponses []*CategoryResponse
	for _, category := range categories {
		categoryResponses = append(categoryResponses, category.ToResponse())
	}

	return &CategoryListResponse{
		Categories: categoryResponses,
		Meta:       pagination.Response(total),
	}, nil
}

// TogglePublish toggles category publish status
func (s *categoryService) TogglePublish(ctx context.Context, id string) (bool, error) {
	// Get category to check if exists
	_, err := s.repository.GetByID(ctx, id)
	if err != nil {
		return false, errors.New("category not found")
	}

	// Toggle publish status
	published, err := s.repository.TogglePublish(ctx, id)
	if err != nil {
		s.logger.Error("Failed to toggle category publish status", map[string]interface{}{
			"error":       err.Error(),
			"category_id": id,
		})
		return false, errors.New("failed to toggle category publish status")
	}

	s.logger.Info("Category publish status updated successfully", map[string]interface{}{
		"category_id": id,
		"published":   published,
	})

	return published, nil
}
