package models

import (
	"context"
	"errors"

	"github.com/timetracker/backend/internal/db"
	"github.com/timetracker/backend/internal/types"
	"gorm.io/gorm"
)

// Customer represents a customer in the system
type Customer struct {
	EntityBase
	Name        string      `gorm:"column:name"`
	CompanyID   *types.ULID `gorm:"type:bytea;column:company_id"`
	OwnerUserID *types.ULID `gorm:"type:bytea;column:owner_user_id"`
}

// TableName specifies the table name for GORM
func (Customer) TableName() string {
	return "customers"
}

// CustomerCreate contains the fields for creating a new customer
type CustomerCreate struct {
	Name        string
	CompanyID   *types.ULID
	OwnerUserID *types.ULID
}

// CustomerUpdate contains the updatable fields of a customer
type CustomerUpdate struct {
	ID          types.ULID  `gorm:"-"` // Exclude from updates
	Name        *string     `gorm:"column:name"`
	CompanyID   *types.ULID `gorm:"column:company_id"`
	OwnerUserID *types.ULID `gorm:"column:owner_user_id"`
}

// GetCustomerByID finds a customer by its ID
func GetCustomerByID(ctx context.Context, id types.ULID) (*Customer, error) {
	var customer Customer
	result := db.GetEngine(ctx).Where("id = ?", id).First(&customer)
	if result.Error != nil {
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, result.Error
	}
	return &customer, nil
}

// GetAllCustomers returns all customers
func GetAllCustomers(ctx context.Context) ([]Customer, error) {
	var customers []Customer
	result := db.GetEngine(ctx).Find(&customers)
	if result.Error != nil {
		return nil, result.Error
	}
	return customers, nil
}

// CreateCustomer creates a new customer
func CreateCustomer(ctx context.Context, create CustomerCreate) (*Customer, error) {
	customer := Customer{
		Name:      create.Name,
		CompanyID: create.CompanyID,
	}

	result := db.GetEngine(ctx).Create(&customer)
	if result.Error != nil {
		return nil, result.Error
	}
	return &customer, nil
}

// UpdateCustomer updates an existing customer
func UpdateCustomer(ctx context.Context, update CustomerUpdate) (*Customer, error) {
	customer, err := GetCustomerByID(ctx, update.ID)
	if err != nil {
		return nil, err
	}
	if customer == nil {
		return nil, errors.New("customer not found")
	}

	// Use generic update function
	if err := UpdateModel(ctx, customer, update); err != nil {
		return nil, err
	}

	// Load updated data from the database
	return GetCustomerByID(ctx, update.ID)
}

// DeleteCustomer deletes a customer by its ID
func DeleteCustomer(ctx context.Context, id types.ULID) error {
	result := db.GetEngine(ctx).Delete(&Customer{}, id)
	return result.Error
}
