package services

import (
	"context"
	"time"

	"payment/internal/models"

	"github.com/go-redis/redis/v8"
	"github.com/google/uuid"
	"gorm.io/gorm"
)

// ClientService handles client operations
type ClientService struct {
	db    *gorm.DB
	redis *redis.Client
}

// NewClientService creates a new client service
func NewClientService(db *gorm.DB, redis *redis.Client) *ClientService {
	return &ClientService{
		db:    db,
		redis: redis,
	}
}

// RegisterClientRequest represents client registration request
type RegisterClientRequest struct {
	// Basic Business Information
	Name               string  `json:"name" binding:"required"`
	BusinessName       *string `json:"business_name"`
	BusinessType       *string `json:"business_type"`
	Industry           *string `json:"industry"`
	RegistrationNumber *string `json:"registration_number"`
	TaxID              *string `json:"tax_id"`
	VATNumber          *string `json:"vat_number"`

	// Contact Information
	Email          string  `json:"email" binding:"required,email"`
	Phone          *string `json:"phone"`
	AlternatePhone *string `json:"alternate_phone"`
	Website        *string `json:"website"`

	// Contact Person
	ContactPersonName  *string `json:"contact_person_name"`
	ContactPersonEmail *string `json:"contact_person_email"`
	ContactPersonPhone *string `json:"contact_person_phone"`

	// Address Information
	Address    *string `json:"address"`
	City       *string `json:"city"`
	State      *string `json:"state"`
	Country    *string `json:"country"`
	PostalCode *string `json:"postal_code"`

	// Additional Information
	Description *string `json:"description"`
	Notes       *string `json:"notes"`
}

// ClientResponse represents client response
type ClientResponse struct {
	ID                 uuid.UUID `json:"id"`
	Name               string    `json:"name"`
	BusinessName       *string   `json:"business_name"`
	BusinessType       *string   `json:"business_type"`
	Industry           *string   `json:"industry"`
	RegistrationNumber *string   `json:"registration_number"`
	TaxID              *string   `json:"tax_id"`
	VATNumber          *string   `json:"vat_number"`
	Email              string    `json:"email"`
	Phone              *string   `json:"phone"`
	AlternatePhone     *string   `json:"alternate_phone"`
	Website            *string   `json:"website"`
	ContactPersonName  *string   `json:"contact_person_name"`
	ContactPersonEmail *string   `json:"contact_person_email"`
	ContactPersonPhone *string   `json:"contact_person_phone"`
	Address            *string   `json:"address"`
	City               *string   `json:"city"`
	State              *string   `json:"state"`
	Country            *string   `json:"country"`
	PostalCode         *string   `json:"postal_code"`
	Description        *string   `json:"description"`
	Notes              *string   `json:"notes"`
	Status             string    `json:"status"`
	IsActive           bool      `json:"is_active"`
	CreatedAt          time.Time `json:"created_at"`
	UpdatedAt          time.Time `json:"updated_at"`
}

// RegisterClient registers a new client
func (s *ClientService) RegisterClient(ctx context.Context, req *RegisterClientRequest) (*ClientResponse, error) {
	// Check if email already exists
	var existingClient models.Client
	if err := s.db.Where("email = ?", req.Email).First(&existingClient).Error; err == nil {
		return nil, gorm.ErrDuplicatedKey
	}

	// Create client
	client := &models.Client{
		Name:               req.Name,
		BusinessName:       req.BusinessName,
		BusinessType:       req.BusinessType,
		Industry:           req.Industry,
		RegistrationNumber: req.RegistrationNumber,
		TaxID:              req.TaxID,
		VATNumber:          req.VATNumber,
		Email:              req.Email,
		Phone:              req.Phone,
		AlternatePhone:     req.AlternatePhone,
		Website:            req.Website,
		ContactPersonName:  req.ContactPersonName,
		ContactPersonEmail: req.ContactPersonEmail,
		ContactPersonPhone: req.ContactPersonPhone,
		Address:            req.Address,
		City:               req.City,
		State:              req.State,
		Country:            req.Country,
		PostalCode:         req.PostalCode,
		Description:        req.Description,
		Notes:              req.Notes,
		Status:             "active",
		IsActive:           true,
	}

	if err := s.db.Create(client).Error; err != nil {
		return nil, err
	}

	return s.mapClientToResponse(client), nil
}

// GetClient retrieves a client by ID
func (s *ClientService) GetClient(ctx context.Context, clientID uuid.UUID) (*ClientResponse, error) {
	var client models.Client
	if err := s.db.Where("id = ? AND is_active = true", clientID).First(&client).Error; err != nil {
		return nil, err
	}

	return s.mapClientToResponse(&client), nil
}

// mapClientToResponse maps a Client model to ClientResponse
func (s *ClientService) mapClientToResponse(client *models.Client) *ClientResponse {
	return &ClientResponse{
		ID:                 client.ID,
		Name:               client.Name,
		BusinessName:       client.BusinessName,
		BusinessType:       client.BusinessType,
		Industry:           client.Industry,
		RegistrationNumber: client.RegistrationNumber,
		TaxID:              client.TaxID,
		VATNumber:          client.VATNumber,
		Email:              client.Email,
		Phone:              client.Phone,
		AlternatePhone:     client.AlternatePhone,
		Website:            client.Website,
		ContactPersonName:  client.ContactPersonName,
		ContactPersonEmail: client.ContactPersonEmail,
		ContactPersonPhone: client.ContactPersonPhone,
		Address:            client.Address,
		City:               client.City,
		State:              client.State,
		Country:            client.Country,
		PostalCode:         client.PostalCode,
		Description:        client.Description,
		Notes:              client.Notes,
		Status:             client.Status,
		IsActive:           client.IsActive,
		CreatedAt:          client.CreatedAt,
		UpdatedAt:          client.UpdatedAt,
	}
}

// SetPaymentCredentials sets payment credentials for a client
func (s *ClientService) SetPaymentCredentials(ctx context.Context, clientID uuid.UUID, credentials *models.PaymentCredentials) error {
	// Check if credentials already exist
	var existing models.PaymentCredentials
	if err := s.db.Where("client_id = ? AND provider = ?", clientID, credentials.Provider).First(&existing).Error; err == nil {
		// Update existing credentials
		existing.ConsumerKey = credentials.ConsumerKey
		existing.ConsumerSecret = credentials.ConsumerSecret
		existing.ShortCode = credentials.ShortCode
		existing.PassKey = credentials.PassKey
		existing.BaseURL = credentials.BaseURL
		existing.CallbackURL = credentials.CallbackURL
		existing.IsActive = credentials.IsActive

		return s.db.Save(&existing).Error
	}

	// Create new credentials
	credentials.ClientID = clientID
	return s.db.Create(credentials).Error
}

// GetPaymentCredentials retrieves payment credentials for a client
func (s *ClientService) GetPaymentCredentials(ctx context.Context, clientID uuid.UUID, provider string) (*models.PaymentCredentials, error) {
	var credentials models.PaymentCredentials
	if err := s.db.Where("client_id = ? AND provider = ? AND is_active = true", clientID, provider).First(&credentials).Error; err != nil {
		return nil, err
	}

	return &credentials, nil
}

// GetAllPaymentCredentials retrieves all payment credentials for a client
func (s *ClientService) GetAllPaymentCredentials(ctx context.Context, clientID uuid.UUID) ([]*models.PaymentCredentials, error) {
	var credentials []*models.PaymentCredentials
	if err := s.db.Where("client_id = ? AND is_active = true", clientID).Find(&credentials).Error; err != nil {
		return nil, err
	}

	return credentials, nil
}

// ValidateClient validates if a client exists and is active
func (s *ClientService) ValidateClient(ctx context.Context, clientID uuid.UUID) error {
	var client models.Client
	if err := s.db.Where("id = ? AND is_active = true", clientID).First(&client).Error; err != nil {
		return err
	}
	return nil
}
