package customer

import (
	"context"
	"errors"
	"time"

	"tm/internal/company"
	"tm/pkg/logger"

	"tm/pkg/authorization"

	"go.mongodb.org/mongo-driver/bson/primitive"
	"golang.org/x/crypto/bcrypt"
)

// Service defines business logic for customer operations
type Service interface {
	// Core customer operations
	CreateCustomer(ctx context.Context, form *CreateCustomerForm, createdBy *string) (*Customer, error)
	GetCustomerByID(ctx context.Context, id string) (*Customer, error)
	GetCustomerByIDWithCompanies(ctx context.Context, id string) (*CustomerResponse, error)
	UpdateCustomer(ctx context.Context, id string, form *UpdateCustomerForm, updatedBy *string) (*Customer, error)
	DeleteCustomer(ctx context.Context, id string, deletedBy *string) error

	// Customer listing and search
	ListCustomers(ctx context.Context, form *ListCustomersForm) (*CustomerListResponse, error)
	GetCustomersByCompanyID(ctx context.Context, companyID string, limit, offset int) ([]*Customer, int64, error)
	GetCustomersByType(ctx context.Context, customerType CustomerType, limit, offset int) ([]*Customer, int64, error)
	GetCustomersByStatus(ctx context.Context, status CustomerStatus, limit, offset int) ([]*Customer, int64, error)

	// Customer management
	UpdateCustomerStatus(ctx context.Context, id string, form *UpdateCustomerStatusForm, updatedBy *string) error
	UpdateCustomerVerification(ctx context.Context, id string, form *UpdateCustomerVerificationForm, updatedBy *string) error

	// Company assignments
	AssignCompaniesToCustomer(ctx context.Context, customerID string, companyIDs []string, updatedBy *string) error
	RemoveCompaniesFromCustomer(ctx context.Context, customerID string, companyIDs []string, updatedBy *string) error

	// Mobile-specific operations (simplified)
	CreateCustomerMobile(ctx context.Context, form *CreateCustomerMobileForm, createdBy *string) (*Customer, error)
	UpdateCustomerMobile(ctx context.Context, id string, form *UpdateCustomerMobileForm, updatedBy *string) (*Customer, error)

	// Business operations
	VerifyCustomer(ctx context.Context, id string, verifiedBy *string) error
	SuspendCustomer(ctx context.Context, id string, reason string, suspendedBy *string) error
	ActivateCustomer(ctx context.Context, id string, activatedBy *string) error

	// Authentication operations
	Login(ctx context.Context, form *LoginForm) (*AuthResponse, error)
	RefreshToken(ctx context.Context, refreshToken string) (*AuthResponse, error)
	GetProfile(ctx context.Context, customerID string) (*Customer, error)
	GetProfileWithCompanies(ctx context.Context, customerID string) (*CustomerResponse, error)
	Logout(ctx context.Context, customerID string, accessToken string) error
}

// customerService implements the Service interface
type customerService struct {
	repository     Repository
	logger         logger.Logger
	authService    authorization.AuthorizationService
	companyService company.Service
}

// NewCustomerService creates a new customer service
func NewCustomerService(repository Repository, logger logger.Logger, authService authorization.AuthorizationService, companyService company.Service) Service {
	return &customerService{
		repository:     repository,
		logger:         logger,
		authService:    authService,
		companyService: companyService,
	}
}

// CreateCustomer creates a new customer
func (s *customerService) CreateCustomer(ctx context.Context, form *CreateCustomerForm, createdBy *string) (*Customer, error) {
	// Check if email already exists
	existingCustomer, _ := s.repository.GetByEmail(ctx, form.Email)
	if existingCustomer != nil {
		return nil, errors.New("customer with this email already exists")
	}

	// Check if registration number already exists (for company customers)
	if form.Type == string(CustomerTypeCompany) && form.RegistrationNumber != nil {
		existingCustomer, _ = s.repository.GetByRegistrationNumber(ctx, *form.RegistrationNumber)
		if existingCustomer != nil {
			return nil, errors.New("company with this registration number already exists")
		}
	}

	// Check if tax ID already exists (for company customers)
	if form.Type == string(CustomerTypeCompany) && form.TaxID != nil {
		existingCustomer, _ = s.repository.GetByTaxID(ctx, *form.TaxID)
		if existingCustomer != nil {
			return nil, errors.New("company with this tax ID already exists")
		}
	}

	// Prepare company assignments
	var companyIDs []string
	if len(form.CompanyIDs) > 0 {
		// Verify that all company IDs exist
		for _, companyID := range form.CompanyIDs {
			_, err := s.companyService.GetCompanyByID(ctx, companyID)
			if err != nil {
				s.logger.Error("Invalid company ID provided", map[string]interface{}{
					"error":      err.Error(),
					"company_id": companyID,
				})
				return nil, errors.New("invalid company ID: " + companyID)
			}
		}
		companyIDs = form.CompanyIDs
	}

	// Hash password
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(form.Password), bcrypt.DefaultCost)
	if err != nil {
		s.logger.Error("Failed to hash password", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, errors.New("failed to process password")
	}

	// Create customer
	customer := &Customer{
		Type:               CustomerType(form.Type),
		Status:             CustomerStatusPending,
		CompanyIDs:         companyIDs,
		FirstName:          form.FirstName,
		LastName:           form.LastName,
		FullName:           form.FullName,
		Username:           form.Username,
		Email:              form.Email,
		Password:           string(hashedPassword),
		Phone:              form.Phone,
		Mobile:             form.Mobile,
		RegistrationNumber: form.RegistrationNumber,
		TaxID:              form.TaxID,
		Industry:           form.Industry,
		Address:            s.convertAddressForm(form.Address),
		BusinessType:       form.BusinessType,
		EmployeeCount:      form.EmployeeCount,
		AnnualRevenue:      form.AnnualRevenue,
		FoundedYear:        form.FoundedYear,
		ContactPerson:      s.convertContactPersonForm(form.ContactPerson),
		IsVerified:         false,
		IsCompliant:        false,
		Language:           s.getDefaultLanguage(form.Language),
		Currency:           s.getDefaultCurrency(form.Currency),
		Timezone:           s.getDefaultTimezone(form.Timezone),
		CreatedBy:          createdBy,
	}

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

	s.logger.Info("Customer created successfully", map[string]interface{}{
		"customer_id": customer.ID,
		"email":       customer.Email,
		"type":        customer.Type,
		"company_ids": companyIDs,
		"created_by":  *createdBy,
	})

	return customer, nil
}

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

	s.logger.Info("Customer retrieved successfully", map[string]interface{}{
		"customer_id": customer.ID,
		"email":       customer.Email,
	})

	return customer, nil
}

// GetCustomerByIDWithCompanies retrieves a customer by ID and loads associated companies
func (s *customerService) GetCustomerByIDWithCompanies(ctx context.Context, id string) (*CustomerResponse, error) {
	customer, err := s.repository.GetByID(ctx, id)
	if err != nil {
		s.logger.Error("Failed to get customer by ID with companies", map[string]interface{}{
			"error":       err.Error(),
			"customer_id": id,
		})
		return nil, err
	}

	// Load companies for the customer
	companies, err := s.loadCompaniesForCustomer(ctx, customer)
	if err != nil {
		s.logger.Error("Failed to load companies for customer", map[string]interface{}{
			"error":       err.Error(),
			"customer_id": customer.ID,
		})
		// Continue without companies if loading fails
		companies = []*CompanySummary{}
	}

	customerResponse := customer.ToResponseWithCompanies(companies)

	s.logger.Info("Customer retrieved with companies successfully", map[string]interface{}{
		"customer_id": customer.ID,
		"email":       customer.Email,
	})

	return customerResponse, nil
}

// UpdateCustomer updates a customer
func (s *customerService) UpdateCustomer(ctx context.Context, id string, form *UpdateCustomerForm, updatedBy *string) (*Customer, error) {
	// Get existing customer
	customer, err := s.repository.GetByID(ctx, id)
	if err != nil {
		s.logger.Error("Failed to get customer for update", map[string]interface{}{
			"error":       err.Error(),
			"customer_id": id,
		})
		return nil, errors.New("customer not found")
	}

	// Check if email already exists (if changing email)
	if form.Email != nil && *form.Email != customer.Email {
		existingCustomer, _ := s.repository.GetByEmail(ctx, *form.Email)
		if existingCustomer != nil {
			return nil, errors.New("customer with this email already exists")
		}
		customer.Email = *form.Email
	}

	// Check if username already exists (if changing username)
	if form.Username != nil && *form.Username != customer.Username {
		existingCustomer, _ := s.repository.GetByUsername(ctx, *form.Username)
		if existingCustomer != nil {
			return nil, errors.New("customer with this username already exists")
		}
		customer.Username = *form.Username
	}

	// Check if registration number already exists (if changing)
	if form.RegistrationNumber != nil && *form.RegistrationNumber != *customer.RegistrationNumber {
		existingCustomer, _ := s.repository.GetByRegistrationNumber(ctx, *form.RegistrationNumber)
		if existingCustomer != nil {
			return nil, errors.New("company with this registration number already exists")
		}
		customer.RegistrationNumber = form.RegistrationNumber
	}

	// Check if tax ID already exists (if changing)
	if form.TaxID != nil && *form.TaxID != *customer.TaxID {
		existingCustomer, _ := s.repository.GetByTaxID(ctx, *form.TaxID)
		if existingCustomer != nil {
			return nil, errors.New("company with this tax ID already exists")
		}
		customer.TaxID = form.TaxID
	}

	// Update fields if provided
	if form.Type != nil {
		customer.Type = CustomerType(*form.Type)
	}

	// Handle company assignments
	if len(form.CompanyIDs) > 0 {
		// Verify that all company IDs exist
		var validCompanyIDs []string
		for _, companyID := range form.CompanyIDs {
			_, err := s.companyService.GetCompanyByID(ctx, companyID)
			if err != nil {
				s.logger.Error("Invalid company ID provided in update", map[string]interface{}{
					"error":      err.Error(),
					"company_id": companyID,
				})
				return nil, errors.New("invalid company ID: " + companyID)
			}
			validCompanyIDs = append(validCompanyIDs, companyID)
		}
		customer.CompanyIDs = validCompanyIDs
	}

	if form.FirstName != nil {
		customer.FirstName = form.FirstName
	}

	if form.LastName != nil {
		customer.LastName = form.LastName
	}

	if form.FullName != nil {
		customer.FullName = form.FullName
	}

	if form.Phone != nil {
		customer.Phone = form.Phone
	}

	if form.Mobile != nil {
		customer.Mobile = form.Mobile
	}

	if form.Industry != nil {
		customer.Industry = form.Industry
	}

	if form.Address != nil {
		customer.Address = s.convertAddressForm(form.Address)
	}

	if form.BusinessType != nil {
		customer.BusinessType = form.BusinessType
	}

	if form.EmployeeCount != nil {
		customer.EmployeeCount = form.EmployeeCount
	}

	if form.AnnualRevenue != nil {
		customer.AnnualRevenue = form.AnnualRevenue
	}

	if form.FoundedYear != nil {
		customer.FoundedYear = form.FoundedYear
	}

	if form.ContactPerson != nil {
		customer.ContactPerson = s.convertContactPersonForm(form.ContactPerson)
	}

	if form.Language != nil {
		customer.Language = *form.Language
	}

	if form.Currency != nil {
		customer.Currency = *form.Currency
	}

	if form.Timezone != nil {
		customer.Timezone = *form.Timezone
	}

	// Set updated by
	customer.UpdatedBy = updatedBy
	customer.UpdatedAt = time.Now().Unix()

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

	s.logger.Info("Customer updated successfully", map[string]interface{}{
		"customer_id": customer.ID,
		"email":       customer.Email,
		"updated_by":  *updatedBy,
	})

	return customer, nil
}

// DeleteCustomer deletes a customer (soft delete)
func (s *customerService) DeleteCustomer(ctx context.Context, id string, deletedBy *string) error {
	// Get customer to check if exists
	customer, err := s.repository.GetByID(ctx, id)
	if err != nil {
		return errors.New("customer not found")
	}

	// Set updated by before deletion
	customer.UpdatedBy = deletedBy

	// Delete customer (soft delete)
	err = s.repository.Delete(ctx, id)
	if err != nil {
		s.logger.Error("Failed to delete customer", map[string]interface{}{
			"error":       err.Error(),
			"customer_id": id,
		})
		return errors.New("failed to delete customer")
	}

	s.logger.Info("Customer deleted successfully", map[string]interface{}{
		"customer_id": id,
		"deleted_by":  deletedBy,
	})

	return nil
}

// ListCustomers lists customers with search and filters
func (s *customerService) ListCustomers(ctx context.Context, form *ListCustomersForm) (*CustomerListResponse, error) {
	// Set defaults
	limit := 20
	if form.Limit != nil {
		limit = *form.Limit
	}

	offset := 0
	if form.Offset != nil {
		offset = *form.Offset
	}

	search := ""
	if form.Search != nil {
		search = *form.Search
	}

	sortBy := "created_at"
	if form.SortBy != nil {
		sortBy = *form.SortBy
	}

	sortOrder := "desc"
	if form.SortOrder != nil {
		sortOrder = *form.SortOrder
	}

	// Parse company ID if provided
	var companyID *string
	if form.CompanyID != nil {
		companyID = form.CompanyID
	}

	// Get customers
	customers, err := s.repository.Search(ctx, search, form.Type, form.Status, companyID, form.Industry, form.IsVerified, form.IsCompliant, form.Language, form.Currency, limit, offset, sortBy, sortOrder)
	if err != nil {
		s.logger.Error("Failed to list customers", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, errors.New("failed to list customers")
	}

	// Convert to responses
	var customerResponses []*CustomerResponse
	for _, customer := range customers {
		customerResponses = append(customerResponses, customer.ToResponse())
	}

	// TODO: Implement proper count for pagination metadata
	total := int64(len(customers)) // This should be a separate count query
	totalPages := (total + int64(limit) - 1) / int64(limit)

	return &CustomerListResponse{
		Customers:  customerResponses,
		Total:      total,
		Limit:      limit,
		Offset:     offset,
		TotalPages: int(totalPages),
	}, nil
}

// GetCustomersByCompanyID retrieves customers by company ID with pagination
func (s *customerService) GetCustomersByCompanyID(ctx context.Context, companyID string, limit, offset int) ([]*Customer, int64, error) {
	customers, err := s.repository.GetByCompanyID(ctx, companyID, limit, offset)
	if err != nil {
		s.logger.Error("Failed to get customers by company ID", map[string]interface{}{
			"error":      err.Error(),
			"company_id": companyID,
		})
		return nil, 0, errors.New("failed to get customers by company")
	}

	// Get total count
	total, err := s.repository.CountByCompanyID(ctx, companyID)
	if err != nil {
		s.logger.Error("Failed to count customers by company ID", map[string]interface{}{
			"error":      err.Error(),
			"company_id": companyID,
		})
		return customers, 0, nil // Return customers even if count fails
	}

	return customers, total, nil
}

// GetCustomersByType retrieves customers by type with pagination
func (s *customerService) GetCustomersByType(ctx context.Context, customerType CustomerType, limit, offset int) ([]*Customer, int64, error) {
	// This would need to be implemented in the repository
	// For now, we'll use the search method
	customerTypeStr := string(customerType)
	customers, err := s.repository.Search(ctx, "", &customerTypeStr, nil, nil, nil, nil, nil, nil, nil, limit, offset, "created_at", "desc")
	if err != nil {
		s.logger.Error("Failed to get customers by type", map[string]interface{}{
			"error":         err.Error(),
			"customer_type": customerType,
		})
		return nil, 0, errors.New("failed to get customers by type")
	}

	// Get total count
	total, err := s.repository.CountByType(ctx, customerType)
	if err != nil {
		s.logger.Error("Failed to count customers by type", map[string]interface{}{
			"error":         err.Error(),
			"customer_type": customerType,
		})
		return customers, 0, nil
	}

	return customers, total, nil
}

// GetCustomersByStatus retrieves customers by status with pagination
func (s *customerService) GetCustomersByStatus(ctx context.Context, status CustomerStatus, limit, offset int) ([]*Customer, int64, error) {
	// This would need to be implemented in the repository
	// For now, we'll use the search method
	statusStr := string(status)
	customers, err := s.repository.Search(ctx, "", nil, &statusStr, nil, nil, nil, nil, nil, nil, limit, offset, "created_at", "desc")
	if err != nil {
		s.logger.Error("Failed to get customers by status", map[string]interface{}{
			"error":  err.Error(),
			"status": status,
		})
		return nil, 0, errors.New("failed to get customers by status")
	}

	// Get total count
	total, err := s.repository.CountByStatus(ctx, status)
	if err != nil {
		s.logger.Error("Failed to count customers by status", map[string]interface{}{
			"error":  err.Error(),
			"status": status,
		})
		return customers, 0, nil
	}

	return customers, total, nil
}

// UpdateCustomerStatus updates customer status
func (s *customerService) UpdateCustomerStatus(ctx context.Context, id string, form *UpdateCustomerStatusForm, updatedBy *string) error {
	// Get customer to check if exists
	_, err := s.repository.GetByID(ctx, id)
	if err != nil {
		return errors.New("customer not found")
	}

	// Update status
	status := CustomerStatus(form.Status)
	err = s.repository.UpdateStatus(ctx, id, status)
	if err != nil {
		s.logger.Error("Failed to update customer status", map[string]interface{}{
			"error":       err.Error(),
			"customer_id": id,
			"status":      form.Status,
		})
		return errors.New("failed to update customer status")
	}

	s.logger.Info("Customer status updated successfully", map[string]interface{}{
		"customer_id": id,
		"status":      form.Status,
		"updated_by":  updatedBy,
	})

	return nil
}

// UpdateCustomerVerification updates customer verification status
func (s *customerService) UpdateCustomerVerification(ctx context.Context, id string, form *UpdateCustomerVerificationForm, updatedBy *string) error {
	// Get customer to check if exists
	_, err := s.repository.GetByID(ctx, id)
	if err != nil {
		return errors.New("customer not found")
	}

	// Update verification
	err = s.repository.UpdateVerification(ctx, id, form.IsVerified, form.IsCompliant, form.ComplianceNotes)
	if err != nil {
		s.logger.Error("Failed to update customer verification", map[string]interface{}{
			"error":       err.Error(),
			"customer_id": id,
		})
		return errors.New("failed to update customer verification")
	}

	s.logger.Info("Customer verification updated successfully", map[string]interface{}{
		"customer_id":  id,
		"is_verified":  form.IsVerified,
		"is_compliant": form.IsCompliant,
		"updated_by":   updatedBy,
	})

	return nil
}

// AssignCompaniesToCustomer assigns companies to a customer
func (s *customerService) AssignCompaniesToCustomer(ctx context.Context, customerID string, companyIDs []string, updatedBy *string) error {
	// Get customer to check if exists
	customer, err := s.repository.GetByID(ctx, customerID)
	if err != nil {
		return errors.New("customer not found")
	}

	// Verify companies exist and update customer's company IDs
	var validCompanyIDs []string
	for _, companyID := range companyIDs {
		_, err = s.companyService.GetCompanyByID(ctx, companyID)
		if err != nil {
			s.logger.Error("Company not found during assignment", map[string]interface{}{
				"error":       err.Error(),
				"customer_id": customerID,
				"company_id":  companyID,
			})
			continue // Skip invalid company IDs
		}
		validCompanyIDs = append(validCompanyIDs, companyID)
	}

	// Update customer's company IDs
	customer.CompanyIDs = append(customer.CompanyIDs, validCompanyIDs...)
	customer.UpdatedBy = updatedBy
	customer.UpdatedAt = time.Now().Unix()

	err = s.repository.Update(ctx, customer)
	if err != nil {
		s.logger.Error("Failed to update customer with company assignments", map[string]interface{}{
			"error":       err.Error(),
			"customer_id": customerID,
		})
		return errors.New("failed to assign companies to customer")
	}

	s.logger.Info("Companies assigned to customer successfully", map[string]interface{}{
		"customer_id": customerID,
		"company_ids": validCompanyIDs,
		"updated_by":  updatedBy,
	})

	return nil
}

// RemoveCompaniesFromCustomer removes companies from a customer
func (s *customerService) RemoveCompaniesFromCustomer(ctx context.Context, customerID string, companyIDs []string, updatedBy *string) error {
	// Get customer to check if exists
	customer, err := s.repository.GetByID(ctx, customerID)
	if err != nil {
		return errors.New("customer not found")
	}

	// Remove company IDs from customer's list
	var updatedCompanyIDs []string
	for _, existingID := range customer.CompanyIDs {
		shouldRemove := false
		for _, removeID := range companyIDs {
			if existingID == removeID {
				shouldRemove = true
				break
			}
		}
		if !shouldRemove {
			updatedCompanyIDs = append(updatedCompanyIDs, existingID)
		}
	}

	// Update customer's company IDs
	customer.CompanyIDs = updatedCompanyIDs
	customer.UpdatedBy = updatedBy
	customer.UpdatedAt = time.Now().Unix()

	err = s.repository.Update(ctx, customer)
	if err != nil {
		s.logger.Error("Failed to update customer after removing company assignments", map[string]interface{}{
			"error":       err.Error(),
			"customer_id": customerID,
		})
		return errors.New("failed to remove companies from customer")
	}

	s.logger.Info("Companies removed from customer successfully", map[string]interface{}{
		"customer_id": customerID,
		"company_ids": companyIDs,
		"updated_by":  updatedBy,
	})

	return nil
}

// CreateCustomerMobile creates a new customer via mobile app (simplified)
func (s *customerService) CreateCustomerMobile(ctx context.Context, form *CreateCustomerMobileForm, createdBy *string) (*Customer, error) {
	// Check if email already exists
	existingCustomer, _ := s.repository.GetByEmail(ctx, form.Email)
	if existingCustomer != nil {
		return nil, errors.New("customer with this email already exists")
	}

	// Prepare company assignments
	var companyIDs []string
	if len(form.CompanyIDs) > 0 {
		// Verify that all company IDs exist
		for _, companyID := range form.CompanyIDs {
			_, err := s.companyService.GetCompanyByID(ctx, companyID)
			if err != nil {
				s.logger.Error("Invalid company ID provided in mobile form", map[string]interface{}{
					"error":      err.Error(),
					"company_id": companyID,
				})
				return nil, errors.New("invalid company ID: " + companyID)
			}
		}
		companyIDs = form.CompanyIDs
	}

	// Create customer with mobile form
	customer := &Customer{
		Type:        CustomerType(form.Type),
		Status:      CustomerStatusActive,
		CompanyIDs:  companyIDs,
		FirstName:   form.FirstName,
		LastName:    form.LastName,
		FullName:    form.FullName,
		Username:    form.Username,
		Email:       form.Email,
		Password:    "", // Will be set after hashing
		Phone:       form.Phone,
		Mobile:      form.Mobile,
		Industry:    form.Industry,
		IsVerified:  false,
		IsCompliant: false,
		Language:    "en",
		Currency:    "USD",
		Timezone:    "UTC",
		CreatedBy:   createdBy,
	}

	// Hash password
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(form.Password), bcrypt.DefaultCost)
	if err != nil {
		s.logger.Error("Failed to hash password for mobile customer", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, errors.New("failed to process password")
	}
	customer.Password = string(hashedPassword)

	// Save to database
	err = s.repository.Create(ctx, customer)
	if err != nil {
		s.logger.Error("Failed to create customer via mobile", map[string]interface{}{
			"error":      err.Error(),
			"email":      form.Email,
			"type":       form.Type,
			"created_by": createdBy,
		})
		return nil, err
	}

	s.logger.Info("Customer created via mobile successfully", map[string]interface{}{
		"customer_id": customer.ID,
		"email":       customer.Email,
		"type":        customer.Type,
		"company_ids": companyIDs,
		"created_by":  *createdBy,
	})

	return customer, nil
}

// UpdateCustomerMobile updates a customer via mobile app (simplified)
func (s *customerService) UpdateCustomerMobile(ctx context.Context, id string, form *UpdateCustomerMobileForm, updatedBy *string) (*Customer, error) {
	// Get existing customer
	customer, err := s.repository.GetByID(ctx, id)
	if err != nil {
		return nil, errors.New("customer not found")
	}

	// Update fields if provided
	if form.FirstName != nil {
		customer.FirstName = form.FirstName
	}

	if form.LastName != nil {
		customer.LastName = form.LastName
	}

	if form.FullName != nil {
		customer.FullName = form.FullName
	}

	if form.Phone != nil {
		customer.Phone = form.Phone
	}

	if form.Mobile != nil {
		customer.Mobile = form.Mobile
	}

	// Handle company assignments
	if len(form.CompanyIDs) > 0 {
		// Verify that all company IDs exist
		var validCompanyIDs []string
		for _, companyID := range form.CompanyIDs {
			_, err := s.companyService.GetCompanyByID(ctx, companyID)
			if err != nil {
				s.logger.Error("Invalid company ID provided in mobile update", map[string]interface{}{
					"error":      err.Error(),
					"company_id": companyID,
				})
				return nil, errors.New("invalid company ID: " + companyID)
			}
			validCompanyIDs = append(validCompanyIDs, companyID)
		}
		customer.CompanyIDs = validCompanyIDs
	}

	if form.Industry != nil {
		customer.Industry = form.Industry
	}

	// Set updated by
	customer.UpdatedBy = updatedBy

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

	s.logger.Info("Customer updated via mobile successfully", map[string]interface{}{
		"customer_id": customer.ID,
		"email":       customer.Email,
		"company_ids": customer.CompanyIDs,
		"updated_by":  *updatedBy,
	})

	return customer, nil
}

// VerifyCustomer verifies a customer
func (s *customerService) VerifyCustomer(ctx context.Context, id string, verifiedBy *string) error {
	// Get customer to check if exists
	customer, err := s.repository.GetByID(ctx, id)
	if err != nil {
		return errors.New("customer not found")
	}

	// Update verification
	err = s.repository.UpdateVerification(ctx, id, true, customer.IsCompliant, customer.ComplianceNotes)
	if err != nil {
		s.logger.Error("Failed to verify customer", map[string]interface{}{
			"error":       err.Error(),
			"customer_id": id,
		})
		return errors.New("failed to verify customer")
	}

	s.logger.Info("Customer verified successfully", map[string]interface{}{
		"customer_id": id,
		"verified_by": verifiedBy,
	})

	return nil
}

// SuspendCustomer suspends a customer
func (s *customerService) SuspendCustomer(ctx context.Context, id string, reason string, suspendedBy *string) error {
	// Get customer to check if exists
	_, err := s.repository.GetByID(ctx, id)
	if err != nil {
		return errors.New("customer not found")
	}

	// Update status to suspended
	err = s.repository.UpdateStatus(ctx, id, CustomerStatusSuspended)
	if err != nil {
		s.logger.Error("Failed to suspend customer", map[string]interface{}{
			"error":       err.Error(),
			"customer_id": id,
		})
		return errors.New("failed to suspend customer")
	}

	s.logger.Info("Customer suspended successfully", map[string]interface{}{
		"customer_id":  id,
		"reason":       reason,
		"suspended_by": suspendedBy,
	})

	return nil
}

// ActivateCustomer activates a customer
func (s *customerService) ActivateCustomer(ctx context.Context, id string, activatedBy *string) error {
	// Get customer to check if exists
	_, err := s.repository.GetByID(ctx, id)
	if err != nil {
		return errors.New("customer not found")
	}

	// Update status to active
	err = s.repository.UpdateStatus(ctx, id, CustomerStatusActive)
	if err != nil {
		s.logger.Error("Failed to activate customer", map[string]interface{}{
			"error":       err.Error(),
			"customer_id": id,
		})
		return errors.New("failed to activate customer")
	}

	s.logger.Info("Customer activated successfully", map[string]interface{}{
		"customer_id":  id,
		"activated_by": activatedBy,
	})

	return nil
}

// Login handles customer authentication
func (s *customerService) Login(ctx context.Context, form *LoginForm) (*AuthResponse, error) {
	s.logger.Info("Customer login attempt", map[string]interface{}{
		"username": form.Username,
	})

	// Get customer by username
	customer, err := s.repository.GetByUsername(ctx, form.Username)
	if err != nil {
		s.logger.Warn("Customer login failed - username not found", map[string]interface{}{
			"username": form.Username,
		})
		return nil, errors.New("invalid credentials")
	}

	// Check if customer is active
	if customer.Status != CustomerStatusActive {
		s.logger.Warn("Customer login failed - account not active", map[string]interface{}{
			"username":    form.Username,
			"customer_id": customer.ID,
			"status":      string(customer.Status),
		})
		return nil, errors.New("account is not active")
	}

	// Verify password
	err = bcrypt.CompareHashAndPassword([]byte(customer.Password), []byte(form.Password))
	if err != nil {
		s.logger.Warn("Customer login failed - wrong password", map[string]interface{}{
			"customer_id": customer.ID,
			"email":       customer.Email,
		})
		return nil, errors.New("invalid credentials")
	}

	// Generate JWT tokens using authorization service
	companyID := ""
	if len(customer.CompanyIDs) > 0 {
		companyID = customer.CompanyIDs[0] // Use first company ID for JWT token
	}

	tokenPair, err := s.authService.GenerateTokenPair(
		customer.ID.Hex(),
		customer.Email,
		"customer", // Role for customers
		companyID,
	)
	if err != nil {
		s.logger.Error("Failed to generate JWT tokens", map[string]interface{}{
			"error":       err.Error(),
			"customer_id": customer.ID,
		})
		return nil, errors.New("failed to generate authentication tokens")
	}

	s.logger.Info("Customer login successful", map[string]interface{}{
		"username":      form.Username,
		"customer_id":   customer.ID,
		"customer_type": string(customer.Type),
	})

	return &AuthResponse{
		Customer:     customer.ToResponse(),
		AccessToken:  tokenPair.AccessToken,
		RefreshToken: tokenPair.RefreshToken,
		ExpiresAt:    time.Now().Add(15 * time.Minute).Unix(), // 15 minutes from now
	}, nil
}

// RefreshToken handles token refresh for customers
func (s *customerService) RefreshToken(ctx context.Context, refreshToken string) (*AuthResponse, error) {
	s.logger.Info("Customer token refresh attempt", map[string]interface{}{
		"refresh_token": refreshToken[:10] + "...", // Log only first 10 chars for security
	})

	// Validate refresh token and generate new access token
	newAccessToken, err := s.authService.RefreshAccessToken(refreshToken)
	if err != nil {
		s.logger.Warn("Failed to refresh access token", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, errors.New("invalid or expired refresh token")
	}

	// Parse the new access token to get customer information
	validationResult, err := s.authService.ValidateAccessToken(newAccessToken)
	if err != nil {
		s.logger.Error("Failed to validate new access token", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, errors.New("failed to generate valid access token")
	}

	if !validationResult.Valid {
		s.logger.Error("New access token validation failed", map[string]interface{}{
			"error": validationResult.Error,
		})
		return nil, errors.New("failed to generate valid access token")
	}

	// Get customer information
	customerID, err := primitive.ObjectIDFromHex(validationResult.Claims.UserID)
	if err != nil {
		s.logger.Error("Failed to parse customer ID from token", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, errors.New("invalid token format")
	}

	customer, err := s.repository.GetByID(ctx, customerID.Hex())
	if err != nil {
		s.logger.Error("Failed to get customer for token refresh", map[string]interface{}{
			"error":       err.Error(),
			"customer_id": customerID.Hex(),
		})
		return nil, errors.New("customer not found")
	}

	// Check if customer is still active
	if customer.Status != CustomerStatusActive {
		return nil, errors.New("customer account is inactive")
	}

	s.logger.Info("Access token refreshed successfully", map[string]interface{}{
		"customer_id":   customer.ID,
		"customer_type": string(customer.Type),
	})

	return &AuthResponse{
		Customer:     customer.ToResponse(),
		AccessToken:  newAccessToken,
		RefreshToken: refreshToken,                            // Return the same refresh token
		ExpiresAt:    time.Now().Add(15 * time.Minute).Unix(), // 15 minutes from now
	}, nil
}

// GetProfile retrieves customer profile information
func (s *customerService) GetProfile(ctx context.Context, customerID string) (*Customer, error) {
	s.logger.Info("Getting customer profile", map[string]interface{}{
		"customer_id": customerID,
	})

	customer, err := s.repository.GetByID(ctx, customerID)
	if err != nil {
		s.logger.Error("Failed to get customer profile", map[string]interface{}{
			"error":       err.Error(),
			"customer_id": customerID,
		})
		return nil, errors.New("customer not found")
	}

	s.logger.Info("Customer profile retrieved successfully", map[string]interface{}{
		"customer_id":   customerID,
		"customer_type": string(customer.Type),
	})

	return customer, nil
}

// GetProfileWithCompanies retrieves customer profile information including companies
func (s *customerService) GetProfileWithCompanies(ctx context.Context, customerID string) (*CustomerResponse, error) {
	s.logger.Info("Getting customer profile with companies", map[string]interface{}{
		"customer_id": customerID,
	})

	customer, err := s.repository.GetByID(ctx, customerID)
	if err != nil {
		s.logger.Error("Failed to get customer profile with companies", map[string]interface{}{
			"error":       err.Error(),
			"customer_id": customerID,
		})
		return nil, errors.New("customer not found")
	}

	// Load companies for the customer
	companies, err := s.loadCompaniesForCustomer(ctx, customer)
	if err != nil {
		s.logger.Error("Failed to load companies for customer profile", map[string]interface{}{
			"error":       err.Error(),
			"customer_id": customer.ID,
		})
		// Continue without companies if loading fails
		companies = []*CompanySummary{}
	}

	customerResponse := customer.ToResponseWithCompanies(companies)

	s.logger.Info("Customer profile retrieved with companies successfully", map[string]interface{}{
		"customer_id":   customerID,
		"customer_type": string(customer.Type),
	})

	return customerResponse, nil
}

// Logout handles customer logout
func (s *customerService) Logout(ctx context.Context, customerID string, accessToken string) error {
	s.logger.Info("Customer logout", map[string]interface{}{
		"customer_id":  customerID,
		"access_token": accessToken[:10] + "...", // Log only first 10 chars for security
	})

	// Invalidate the access token
	err := s.authService.InvalidateToken(accessToken)
	if err != nil {
		s.logger.Error("Failed to invalidate access token", map[string]interface{}{
			"error":       err.Error(),
			"customer_id": customerID,
		})
		// Don't return error here as the customer should still be logged out
	}

	s.logger.Info("Customer logout successful", map[string]interface{}{
		"customer_id": customerID,
	})

	return nil
}

// Helper methods for converting forms to domain objects
func (s *customerService) convertAddressForm(form *AddressForm) *Address {
	if form == nil {
		return nil
	}

	return &Address{
		Street:      form.Street,
		City:        form.City,
		State:       form.State,
		PostalCode:  form.PostalCode,
		Country:     form.Country,
		AddressType: form.AddressType,
		IsDefault:   form.IsDefault,
	}
}

func (s *customerService) convertContactPersonForm(form *ContactPersonForm) *ContactPerson {
	if form == nil {
		return nil
	}

	return &ContactPerson{
		FirstName: form.FirstName,
		LastName:  form.LastName,
		FullName:  form.FullName,
		Position:  form.Position,
		Email:     form.Email,
		Phone:     form.Phone,
		Mobile:    form.Mobile,
		IsPrimary: form.IsPrimary,
	}
}

func (s *customerService) getDefaultLanguage(language *string) string {
	if language != nil {
		return *language
	}
	return "en"
}

func (s *customerService) getDefaultCurrency(currency *string) string {
	if currency != nil {
		return *currency
	}
	return "USD"
}

func (s *customerService) getDefaultTimezone(timezone *string) string {
	if timezone != nil {
		return *timezone
	}
	return "UTC"
}

// loadCompaniesForCustomer loads company summaries for a customer
func (s *customerService) loadCompaniesForCustomer(ctx context.Context, customer *Customer) ([]*CompanySummary, error) {
	if len(customer.CompanyIDs) == 0 {
		return []*CompanySummary{}, nil
	}

	// Load companies in batch using the new GetCompaniesByIDs method
	companies, err := s.companyService.GetCompaniesByIDs(ctx, customer.CompanyIDs)
	if err != nil {
		s.logger.Error("Failed to load companies for customer", map[string]interface{}{
			"error":       err.Error(),
			"customer_id": customer.ID,
			"company_ids": customer.CompanyIDs,
		})
		return []*CompanySummary{}, err
	}

	// Convert to CompanySummary format
	var companySummaries []*CompanySummary
	for _, company := range companies {
		companySummaries = append(companySummaries, &CompanySummary{
			ID:   company.ID.Hex(),
			Name: company.Name,
		})
	}

	s.logger.Info("Companies loaded for customer", map[string]interface{}{
		"customer_id":     customer.ID,
		"requested_count": len(customer.CompanyIDs),
		"loaded_count":    len(companySummaries),
	})

	return companySummaries, nil
}
