package repository

import (
	"web-qudo-be/app/database"
	"web-qudo-be/app/database/entity"
	"web-qudo-be/app/module/schedules/request"
	"web-qudo-be/utils/paginator"

	"github.com/google/uuid"
)

type SchedulesRepository interface {
	All(clientId *uuid.UUID, req request.SchedulesQueryRequest) ([]*entity.Schedules, *paginator.Pagination, error)
	Show(clientId *uuid.UUID, id uint) (*entity.Schedules, error)
	Save(clientId *uuid.UUID, schedule *entity.Schedules) (*entity.Schedules, error)
	Update(clientId *uuid.UUID, id uint, schedule *entity.Schedules) error
	Delete(clientId *uuid.UUID, id uint) error
	Count(clientId *uuid.UUID, req request.SchedulesQueryRequest) (int64, error)
}

type schedulesRepository struct {
	db *database.Database
}

func NewSchedulesRepository(db *database.Database) SchedulesRepository {
	return &schedulesRepository{
		db: db,
	}
}

func (_i *schedulesRepository) All(clientId *uuid.UUID, req request.SchedulesQueryRequest) ([]*entity.Schedules, *paginator.Pagination, error) {
	var schedules []*entity.Schedules
	var total int64

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

	// Apply client filter
	if clientId != nil {
		query = query.Where("client_id = ?", *clientId)
	}

	// Apply filters
	if req.Title != nil {
		query = query.Where("title ILIKE ?", "%"+*req.Title+"%")
	}
	if req.Description != nil {
		query = query.Where("description ILIKE ?", "%"+*req.Description+"%")
	}
	if req.Location != nil {
		query = query.Where("location ILIKE ?", "%"+*req.Location+"%")
	}
	if req.TypeId != nil {
		query = query.Where("type_id = ?", *req.TypeId)
	}
	if req.StartDate != nil {
		query = query.Where("start_date >= ?", *req.StartDate)
	}
	if req.EndDate != nil {
		query = query.Where("end_date <= ?", *req.EndDate)
	}
	if req.IsLiveStreaming != nil {
		query = query.Where("is_live_streaming = ?", *req.IsLiveStreaming)
	}
	if req.Speakers != nil {
		query = query.Where("speakers ILIKE ?", "%"+*req.Speakers+"%")
	}
	if req.StatusId != nil {
		query = query.Where("status_id = ?", *req.StatusId)
	}
	if req.CreatedById != nil {
		query = query.Where("created_by_id = ?", *req.CreatedById)
	}

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

	// Apply pagination
	if req.Pagination != nil {
		offset := (req.Pagination.Page - 1) * req.Pagination.Limit
		query = query.Offset(offset).Limit(req.Pagination.Limit)
	}

	// Order by created_at desc
	query = query.Order("created_at DESC")

	// Execute query
	if err := query.Find(&schedules).Error; err != nil {
		return nil, nil, err
	}

	// Create pagination response
	pagination := &paginator.Pagination{
		Page:      req.Pagination.Page,
		Limit:     req.Pagination.Limit,
		Count:     total,
		TotalPage: int((total + int64(req.Pagination.Limit) - 1) / int64(req.Pagination.Limit)),
	}

	return schedules, pagination, nil
}

func (_i *schedulesRepository) Show(clientId *uuid.UUID, id uint) (*entity.Schedules, error) {
	var schedule entity.Schedules

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

	// Apply client filter
	if clientId != nil {
		query = query.Where("client_id = ?", *clientId)
	}

	if err := query.Where("id = ?", id).First(&schedule).Error; err != nil {
		return nil, err
	}

	return &schedule, nil
}

func (_i *schedulesRepository) Save(clientId *uuid.UUID, schedule *entity.Schedules) (*entity.Schedules, error) {
	schedule.ClientId = clientId

	if err := _i.db.DB.Create(schedule).Error; err != nil {
		return nil, err
	}

	return schedule, nil
}

func (_i *schedulesRepository) Update(clientId *uuid.UUID, id uint, schedule *entity.Schedules) error {
	query := _i.db.DB.Model(&entity.Schedules{})

	// Apply client filter
	if clientId != nil {
		query = query.Where("client_id = ?", *clientId)
	}

	return query.Where("id = ?", id).Updates(schedule).Error
}

func (_i *schedulesRepository) Delete(clientId *uuid.UUID, id uint) error {
	query := _i.db.DB.Model(&entity.Schedules{})

	// Apply client filter
	if clientId != nil {
		query = query.Where("client_id = ?", *clientId)
	}

	return query.Where("id = ?", id).Delete(&entity.Schedules{}).Error
}

func (_i *schedulesRepository) Count(clientId *uuid.UUID, req request.SchedulesQueryRequest) (int64, error) {
	var total int64

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

	// Apply client filter
	if clientId != nil {
		query = query.Where("client_id = ?", *clientId)
	}

	// Apply filters
	if req.Title != nil {
		query = query.Where("title ILIKE ?", "%"+*req.Title+"%")
	}
	if req.Description != nil {
		query = query.Where("description ILIKE ?", "%"+*req.Description+"%")
	}
	if req.Location != nil {
		query = query.Where("location ILIKE ?", "%"+*req.Location+"%")
	}
	if req.TypeId != nil {
		query = query.Where("type_id = ?", *req.TypeId)
	}
	if req.StartDate != nil {
		query = query.Where("start_date >= ?", *req.StartDate)
	}
	if req.EndDate != nil {
		query = query.Where("end_date <= ?", *req.EndDate)
	}
	if req.IsLiveStreaming != nil {
		query = query.Where("is_live_streaming = ?", *req.IsLiveStreaming)
	}
	if req.Speakers != nil {
		query = query.Where("speakers ILIKE ?", "%"+*req.Speakers+"%")
	}
	if req.StatusId != nil {
		query = query.Where("status_id = ?", *req.StatusId)
	}
	if req.CreatedById != nil {
		query = query.Where("created_by_id = ?", *req.CreatedById)
	}

	return total, query.Count(&total).Error
}
