package repository

import (
	"narasi-ahli-be/app/database"
	"narasi-ahli-be/app/database/entity"
	"narasi-ahli-be/app/module/chat/request"
	"narasi-ahli-be/utils/paginator"
)

type chatScheduleRepository struct {
	DB *database.Database
}

type ChatScheduleRepository interface {
	// Chat Schedule CRUD operations
	CreateChatSchedule(schedule *entity.ChatSchedules) (result *entity.ChatSchedules, err error)
	GetAllChatSchedules(userId uint, req request.ChatScheduleQueryRequest) (schedules []*entity.ChatSchedules, paging paginator.Pagination, err error)
	GetChatScheduleByID(id uint) (schedule *entity.ChatSchedules, err error)
	UpdateChatSchedule(id uint, schedule *entity.ChatSchedules) (err error)
	DeleteChatSchedule(id uint) (err error)

	// Chat Schedule File operations
	CreateChatScheduleFile(file *entity.ChatScheduleFiles) (result *entity.ChatScheduleFiles, err error)
	GetChatScheduleFilesByScheduleID(scheduleID uint) (files []*entity.ChatScheduleFiles, err error)
	UpdateChatScheduleFile(id uint, file *entity.ChatScheduleFiles) (err error)
	DeleteChatScheduleFile(id uint) (err error)

	// Utility methods
	CheckUserInChatSchedule(userId uint, scheduleID uint) (isParticipant bool, err error)
	GetUpcomingSchedules(userId uint, limit int) (schedules []*entity.ChatSchedules, err error)
	GetSchedulesByStatus(status string) (schedules []*entity.ChatSchedules, err error)
}

func NewChatScheduleRepository(db *database.Database) ChatScheduleRepository {
	return &chatScheduleRepository{
		DB: db,
	}
}

// Chat Schedule Repository Methods
func (_i *chatScheduleRepository) CreateChatSchedule(schedule *entity.ChatSchedules) (result *entity.ChatSchedules, err error) {
	err = _i.DB.DB.Create(schedule).Error
	if err != nil {
		return nil, err
	}

	err = _i.DB.DB.Preload("Creator").
		Preload("ChatSession").
		Preload("Files").
		First(&result, schedule.ID).Error
	return
}

func (_i *chatScheduleRepository) GetAllChatSchedules(userId uint, req request.ChatScheduleQueryRequest) (schedules []*entity.ChatSchedules, paging paginator.Pagination, err error) {
	// Get chat schedules where user is a participant in the chat session
	query := _i.DB.DB.Model(&entity.ChatSchedules{}).
		Joins("INNER JOIN chat_sessions cs ON chat_schedules.chat_session_id = cs.id").
		Joins("INNER JOIN chat_participants cp ON cs.id = cp.chat_session_id").
		Where("cp.user_id = ? AND cp.is_active = true", userId)

	// Apply filters
	if req.ChatSessionID != nil {
		query = query.Where("chat_schedules.chat_session_id = ?", *req.ChatSessionID)
	}

	if req.Status != nil {
		query = query.Where("chat_schedules.status = ?", *req.Status)
	}

	if req.CreatedBy != nil {
		query = query.Where("chat_schedules.created_by = ?", *req.CreatedBy)
	}

	if req.DateFrom != nil {
		query = query.Where("DATE(chat_schedules.scheduled_at) >= ?", req.DateFrom.Format("2006-01-02"))
	}

	if req.DateTo != nil {
		query = query.Where("DATE(chat_schedules.scheduled_at) <= ?", req.DateTo.Format("2006-01-02"))
	}

	// Include relationships
	query = query.Preload("Creator").
		Preload("ChatSession").
		Preload("Files")

	// Order by scheduled_at asc (upcoming first)
	query = query.Order("chat_schedules.scheduled_at ASC")

	// Apply pagination
	var count int64
	query.Count(&count)
	req.Pagination.Count = count
	pagingResult := paginator.Paging(&req.Pagination)

	err = query.Offset(pagingResult.Offset).Limit(pagingResult.Limit).Find(&schedules).Error
	paging = *pagingResult

	return
}

func (_i *chatScheduleRepository) GetChatScheduleByID(id uint) (schedule *entity.ChatSchedules, err error) {
	err = _i.DB.DB.Preload("Creator").
		Preload("ChatSession").
		Preload("Files").
		First(&schedule, id).Error
	return
}

func (_i *chatScheduleRepository) UpdateChatSchedule(id uint, schedule *entity.ChatSchedules) (err error) {
	err = _i.DB.DB.Model(&entity.ChatSchedules{}).Where("id = ?", id).Updates(schedule).Error
	return
}

func (_i *chatScheduleRepository) DeleteChatSchedule(id uint) (err error) {
	err = _i.DB.DB.Delete(&entity.ChatSchedules{}, id).Error
	return
}

// Chat Schedule File Repository Methods
func (_i *chatScheduleRepository) CreateChatScheduleFile(file *entity.ChatScheduleFiles) (result *entity.ChatScheduleFiles, err error) {
	err = _i.DB.DB.Create(file).Error
	if err != nil {
		return nil, err
	}

	err = _i.DB.DB.First(&result, file.ID).Error
	return
}

func (_i *chatScheduleRepository) GetChatScheduleFilesByScheduleID(scheduleID uint) (files []*entity.ChatScheduleFiles, err error) {
	err = _i.DB.DB.Model(&entity.ChatScheduleFiles{}).Where("chat_schedule_id = ?", scheduleID).Find(&files).Error
	return
}

func (_i *chatScheduleRepository) UpdateChatScheduleFile(id uint, file *entity.ChatScheduleFiles) (err error) {
	err = _i.DB.DB.Model(&entity.ChatScheduleFiles{}).Where("id = ?", id).Updates(file).Error
	return
}

func (_i *chatScheduleRepository) DeleteChatScheduleFile(id uint) (err error) {
	err = _i.DB.DB.Delete(&entity.ChatScheduleFiles{}, id).Error
	return
}

// Utility Methods
func (_i *chatScheduleRepository) CheckUserInChatSchedule(userId uint, scheduleID uint) (isParticipant bool, err error) {
	err = _i.DB.DB.Model(&entity.ChatParticipants{}).
		Select("COUNT(*) > 0").
		Joins("INNER JOIN chat_sessions cs ON chat_participants.chat_session_id = cs.id").
		Where("cs.id = ? AND chat_participants.user_id = ? AND chat_participants.is_active = true", scheduleID, userId).
		Scan(&isParticipant).Error
	return
}

func (_i *chatScheduleRepository) GetUpcomingSchedules(userId uint, limit int) (schedules []*entity.ChatSchedules, err error) {
	err = _i.DB.DB.Model(&entity.ChatSchedules{}).
		Joins("INNER JOIN chat_sessions cs ON chat_schedules.chat_session_id = cs.id").
		Joins("INNER JOIN chat_participants cp ON cs.id = cp.chat_session_id").
		Where("cp.user_id = ? AND cp.is_active = true AND chat_schedules.scheduled_at > NOW() AND chat_schedules.status = 'scheduled'", userId).
		Preload("Creator").
		Preload("ChatSession").
		Preload("Files").
		Order("chat_schedules.scheduled_at ASC").
		Limit(limit).
		Find(&schedules).Error
	return
}

func (_i *chatScheduleRepository) GetSchedulesByStatus(status string) (schedules []*entity.ChatSchedules, err error) {
	err = _i.DB.DB.Model(&entity.ChatSchedules{}).
		Where("status = ?", status).
		Preload("Creator").
		Preload("ChatSession").
		Preload("Files").
		Order("scheduled_at ASC").
		Find(&schedules).Error
	return
}
