package repository

import (
	"context"
	"strings"

	"github.com/google/uuid"

	"apskel-pos-be/internal/entities"

	"gorm.io/gorm"
)

type VendorRepositoryImpl struct {
	db *gorm.DB
}

func NewVendorRepositoryImpl(db *gorm.DB) *VendorRepositoryImpl {
	return &VendorRepositoryImpl{
		db: db,
	}
}

func (r *VendorRepositoryImpl) Create(ctx context.Context, vendor *entities.Vendor) error {
	return r.db.WithContext(ctx).Create(vendor).Error
}

func (r *VendorRepositoryImpl) GetByID(ctx context.Context, id uuid.UUID) (*entities.Vendor, error) {
	var vendor entities.Vendor
	err := r.db.WithContext(ctx).First(&vendor, "id = ?", id).Error
	if err != nil {
		return nil, err
	}
	return &vendor, nil
}

func (r *VendorRepositoryImpl) GetByIDAndOrganizationID(ctx context.Context, id, organizationID uuid.UUID) (*entities.Vendor, error) {
	var vendor entities.Vendor
	err := r.db.WithContext(ctx).Where("id = ? AND organization_id = ?", id, organizationID).First(&vendor).Error
	if err != nil {
		return nil, err
	}
	return &vendor, nil
}

func (r *VendorRepositoryImpl) Update(ctx context.Context, vendor *entities.Vendor) error {
	return r.db.WithContext(ctx).Save(vendor).Error
}

func (r *VendorRepositoryImpl) Delete(ctx context.Context, id uuid.UUID) error {
	return r.db.WithContext(ctx).Delete(&entities.Vendor{}, "id = ?", id).Error
}

func (r *VendorRepositoryImpl) List(ctx context.Context, organizationID uuid.UUID, filters map[string]interface{}, limit, offset int) ([]*entities.Vendor, int64, error) {
	var vendors []*entities.Vendor
	var total int64

	query := r.db.WithContext(ctx).Model(&entities.Vendor{}).Where("organization_id = ?", organizationID)

	// Apply filters
	for key, value := range filters {
		switch key {
		case "search":
			if searchStr, ok := value.(string); ok && searchStr != "" {
				searchPattern := "%" + strings.ToLower(searchStr) + "%"
				query = query.Where("LOWER(name) LIKE ? OR LOWER(email) LIKE ? OR LOWER(contact_person) LIKE ?",
					searchPattern, searchPattern, searchPattern)
			}
		case "is_active":
			if isActive, ok := value.(bool); ok {
				query = query.Where("is_active = ?", isActive)
			}
		default:
			query = query.Where(key+" = ?", value)
		}
	}

	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	err := query.Order("created_at DESC").Limit(limit).Offset(offset).Find(&vendors).Error
	return vendors, total, err
}

func (r *VendorRepositoryImpl) Count(ctx context.Context, organizationID uuid.UUID, filters map[string]interface{}) (int64, error) {
	var count int64
	query := r.db.WithContext(ctx).Model(&entities.Vendor{}).Where("organization_id = ?", organizationID)

	// Apply filters
	for key, value := range filters {
		switch key {
		case "search":
			if searchStr, ok := value.(string); ok && searchStr != "" {
				searchPattern := "%" + strings.ToLower(searchStr) + "%"
				query = query.Where("LOWER(name) LIKE ? OR LOWER(email) LIKE ? OR LOWER(contact_person) LIKE ?",
					searchPattern, searchPattern, searchPattern)
			}
		case "is_active":
			if isActive, ok := value.(bool); ok {
				query = query.Where("is_active = ?", isActive)
			}
		default:
			query = query.Where(key+" = ?", value)
		}
	}

	err := query.Count(&count).Error
	return count, err
}

func (r *VendorRepositoryImpl) GetByEmail(ctx context.Context, email string, organizationID uuid.UUID) (*entities.Vendor, error) {
	var vendor entities.Vendor
	err := r.db.WithContext(ctx).Where("email = ? AND organization_id = ?", email, organizationID).First(&vendor).Error
	if err != nil {
		return nil, err
	}
	return &vendor, nil
}

func (r *VendorRepositoryImpl) GetByName(ctx context.Context, name string, organizationID uuid.UUID) (*entities.Vendor, error) {
	var vendor entities.Vendor
	err := r.db.WithContext(ctx).Where("name = ? AND organization_id = ?", name, organizationID).First(&vendor).Error
	if err != nil {
		return nil, err
	}
	return &vendor, nil
}

func (r *VendorRepositoryImpl) GetActiveVendors(ctx context.Context, organizationID uuid.UUID) ([]*entities.Vendor, error) {
	var vendors []*entities.Vendor
	err := r.db.WithContext(ctx).Where("organization_id = ? AND is_active = ?", organizationID, true).Find(&vendors).Error
	return vendors, err
}
