package repository

import (
	"fmt"
	"netidhub-saas-be/app/database"
	"netidhub-saas-be/app/database/entity"
	"netidhub-saas-be/app/module/clients/request"
	"netidhub-saas-be/utils/client"
	"netidhub-saas-be/utils/paginator"
	"strings"

	"github.com/google/uuid"
	"github.com/rs/zerolog"
	"gorm.io/gorm"
)

type clientsRepository struct {
	DB  *database.Database
	Log zerolog.Logger
}

// ClientsRepository define interface of IClientsRepository
type ClientsRepository interface {
	GetAll(req request.ClientsQueryRequest) (clientss []*entity.Clients, paging paginator.Pagination, err error)
	FindOne(id uuid.UUID) (clients *entity.Clients, err error)
	Create(clients *entity.Clients) (clientsReturn *entity.Clients, err error)
	Update(id uuid.UUID, clients *entity.Clients) (err error)
	Delete(id uuid.UUID) (err error)

	// New hierarchy methods
	GetWithHierarchy(clientId uuid.UUID) (*entity.Clients, error)
	GetSubClients(parentId uuid.UUID, includeInactive bool) ([]entity.Clients, error)
	GetAllSubClients(parentId uuid.UUID) ([]entity.Clients, error)
	GetRootClients() ([]entity.Clients, error)
	GetClientStats(clientId uuid.UUID) (map[string]interface{}, error)
	MoveClient(clientId, newParentId uuid.UUID) error
	IsParentClient(clientId uuid.UUID) (bool, error)
}

func NewClientsRepository(db *database.Database, logger zerolog.Logger) ClientsRepository {
	return &clientsRepository{
		DB:  db,
		Log: logger,
	}
}

// implement interface of IClientsRepository
func (_i *clientsRepository) GetAll(req request.ClientsQueryRequest) (clientss []*entity.Clients, paging paginator.Pagination, err error) {
	var count int64

	query := _i.DB.DB.Model(&entity.Clients{})

	// Name filter
	if req.Name != nil && *req.Name != "" {
		name := strings.ToLower(*req.Name)
		query = query.Where("LOWER(name) LIKE ?", "%"+strings.ToLower(name)+"%")
	}

	// Type filter
	if req.ClientType != nil && *req.ClientType != "" && *req.ClientType != "all" {
		query = query.Where("client_type = ?", *req.ClientType)
	}

	// Parent filter
	if req.ParentClientId != nil {
		query = query.Where("parent_client_id = ?", *req.ParentClientId)
	}

	// Only parent clients
	if req.OnlyParentClients != nil && *req.OnlyParentClients {
		query = query.Where("id IN (SELECT DISTINCT parent_client_id FROM clients WHERE parent_client_id IS NOT NULL)")
	}

	// Only standalone
	if req.OnlyStandalone != nil && *req.OnlyStandalone {
		query = query.Where("client_type = ?", "standalone")
	}
	
	// Active filter
	if req.IsActive != nil {
		query = query.Where("is_active = ?", *req.IsActive)
	} else {
		query = query.Where("is_active = ?", true) // Default: only active
	}

	// Preload relationships
	query = query.Preload("ParentClient").Preload("SubClients", "is_active = ?", true)

	// Count total records
	query.Count(&count)

	// Apply sorting
	if req.Pagination.SortBy != "" {
		direction := "ASC"
		if req.Pagination.Sort == "desc" {
			direction = "DESC"
		}
		query.Order(fmt.Sprintf("%s %s", req.Pagination.SortBy, direction))
	} else {
		direction := "DESC"
		sortBy := "created_at"
		query.Order(fmt.Sprintf("%s %s", sortBy, direction))
	}

	// Apply pagination (manual calculation for better performance)
	page := req.Pagination.Page
	limit := req.Pagination.Limit
	if page <= 0 {
		page = 1
	}
	if limit <= 0 {
		limit = 10
	}

	offset := (page - 1) * limit
	err = query.Offset(offset).Limit(limit).Find(&clientss).Error
	if err != nil {
		return
	}

	// Create pagination response
	paging = paginator.Pagination{
		Page:      page,
		Limit:     limit,
		Count:     count,
		TotalPage: int((count + int64(limit) - 1) / int64(limit)),
	}

	return
}

func (_i *clientsRepository) FindOne(id uuid.UUID) (clients *entity.Clients, err error) {
	if err := _i.DB.DB.First(&clients, id).Error; err != nil {
		return nil, err
	}

	return clients, nil
}

func (_i *clientsRepository) Create(clients *entity.Clients) (clientsReturn *entity.Clients, err error) {
	result := _i.DB.DB.Create(clients)
	return clients, result.Error
}

func (_i *clientsRepository) Update(id uuid.UUID, clients *entity.Clients) (err error) {
	return _i.DB.DB.Model(&entity.Clients{}).
		Where(&entity.Clients{ID: id}).
		Updates(clients).Error
}

func (_i *clientsRepository) Delete(id uuid.UUID) error {
	return _i.DB.DB.Delete(&entity.Clients{}, id).Error
}

// =====================================================================
// NEW HIERARCHY METHODS
// =====================================================================

// GetWithHierarchy gets client with parent and sub-clients loaded
func (_i *clientsRepository) GetWithHierarchy(clientId uuid.UUID) (*entity.Clients, error) {
	var client entity.Clients
	err := _i.DB.DB.Preload("ParentClient").
		Preload("SubClients", "is_active = ?", true).
		Where("id = ?", clientId).
		First(&client).Error
	return &client, err
}

// GetSubClients gets direct children of a client
func (_i *clientsRepository) GetSubClients(parentId uuid.UUID, includeInactive bool) ([]entity.Clients, error) {
	var clients []entity.Clients
	query := _i.DB.DB.Where("parent_client_id = ?", parentId)

	if !includeInactive {
		query = query.Where("is_active = ?", true)
	}

	err := query.Find(&clients).Error
	return clients, err
}

// GetAllSubClients gets all descendants recursively
func (_i *clientsRepository) GetAllSubClients(parentId uuid.UUID) ([]entity.Clients, error) {
	subClientIDs, err := client.GetSubClientIDs(_i.DB.DB, parentId)
	if err != nil || len(subClientIDs) == 0 {
		return []entity.Clients{}, err
	}

	var clients []entity.Clients
	err = _i.DB.DB.Where("id IN ?", subClientIDs).Find(&clients).Error
	return clients, err
}

// GetRootClients gets all clients without parent
func (_i *clientsRepository) GetRootClients() ([]entity.Clients, error) {
	var clients []entity.Clients
	err := _i.DB.DB.Where("parent_client_id IS NULL AND is_active = ?", true).
		Find(&clients).Error
	return clients, err
}

// GetClientStats gets statistics for a client
func (_i *clientsRepository) GetClientStats(clientId uuid.UUID) (map[string]interface{}, error) {
	stats := make(map[string]interface{})

	// Count users
	var userCount int64
	_i.DB.DB.Model(&entity.Users{}).Where("client_id = ? AND is_active = ?", clientId, true).Count(&userCount)
	stats["total_users"] = userCount

	// Count articles
	var articleCount int64
	_i.DB.DB.Model(&entity.Articles{}).Where("client_id = ? AND is_active = ?", clientId, true).Count(&articleCount)
	stats["total_articles"] = articleCount

	// Count sub-clients
	var subClientCount int64
	_i.DB.DB.Model(&entity.Clients{}).Where("parent_client_id = ? AND is_active = ?", clientId, true).Count(&subClientCount)
	stats["sub_client_count"] = subClientCount

	return stats, nil
}

// MoveClient moves a client to a different parent
func (_i *clientsRepository) MoveClient(clientId, newParentId uuid.UUID) error {
	// Validate no circular reference
	if newParentId != uuid.Nil {
		// Check if newParent is a descendant of client (would create circle)
		descendants, _ := client.GetSubClientIDs(_i.DB.DB, clientId)
		for _, descId := range descendants {
			if descId == newParentId {
				return gorm.ErrInvalidData // Circular reference
			}
		}
	}

	return _i.DB.DB.Model(&entity.Clients{}).
		Where("id = ?", clientId).
		Update("parent_client_id", newParentId).Error
}

// IsParentClient checks if client has children
func (_i *clientsRepository) IsParentClient(clientId uuid.UUID) (bool, error) {
	var count int64
	err := _i.DB.DB.Model(&entity.Clients{}).
		Where("parent_client_id = ? AND is_active = ?", clientId, true).
		Count(&count).Error
	return count > 0, err
}
