package repository

import (
	"context"
	"time"

	"eslogad-be/internal/entities"

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

type VoteEventRepositoryImpl struct {
	db *gorm.DB
}

func NewVoteEventRepository(db *gorm.DB) *VoteEventRepositoryImpl {
	return &VoteEventRepositoryImpl{
		db: db,
	}
}

func (r *VoteEventRepositoryImpl) Create(ctx context.Context, voteEvent *entities.VoteEvent) error {
	return r.db.WithContext(ctx).Create(voteEvent).Error
}

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

func (r *VoteEventRepositoryImpl) GetActiveEvents(ctx context.Context) ([]*entities.VoteEvent, error) {
	var events []*entities.VoteEvent
	now := time.Now()
	err := r.db.WithContext(ctx).
		Preload("Candidates").
		Where("is_active = ? AND start_date <= ? AND end_date >= ?", true, now, now).
		Find(&events).Error
	return events, err
}

func (r *VoteEventRepositoryImpl) List(ctx context.Context, limit, offset int) ([]*entities.VoteEvent, int64, error) {
	var events []*entities.VoteEvent
	var total int64

	if err := r.db.WithContext(ctx).Model(&entities.VoteEvent{}).Count(&total).Error; err != nil {
		return nil, 0, err
	}

	err := r.db.WithContext(ctx).
		Preload("Candidates").
		Limit(limit).
		Offset(offset).
		Order("created_at DESC").
		Find(&events).Error
	return events, total, err
}

func (r *VoteEventRepositoryImpl) Update(ctx context.Context, voteEvent *entities.VoteEvent) error {
	return r.db.WithContext(ctx).Save(voteEvent).Error
}

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

func (r *VoteEventRepositoryImpl) CreateCandidate(ctx context.Context, candidate *entities.Candidate) error {
	return r.db.WithContext(ctx).Create(candidate).Error
}

func (r *VoteEventRepositoryImpl) GetCandidatesByEventID(ctx context.Context, eventID uuid.UUID) ([]*entities.Candidate, error) {
	var candidates []*entities.Candidate
	err := r.db.WithContext(ctx).
		Where("vote_event_id = ?", eventID).
		Find(&candidates).Error
	return candidates, err
}

func (r *VoteEventRepositoryImpl) SubmitVote(ctx context.Context, vote *entities.Vote) error {
	return r.db.WithContext(ctx).Create(vote).Error
}

func (r *VoteEventRepositoryImpl) HasUserVoted(ctx context.Context, userID, eventID uuid.UUID) (bool, error) {
	var count int64
	err := r.db.WithContext(ctx).
		Model(&entities.Vote{}).
		Where("user_id = ? AND vote_event_id = ?", userID, eventID).
		Count(&count).Error
	return count > 0, err
}

func (r *VoteEventRepositoryImpl) GetVoteResults(ctx context.Context, eventID uuid.UUID) (map[uuid.UUID]int64, error) {
	type result struct {
		CandidateID uuid.UUID
		VoteCount   int64
	}

	var results []result
	err := r.db.WithContext(ctx).
		Model(&entities.Vote{}).
		Select("candidate_id, COUNT(*) as vote_count").
		Where("vote_event_id = ?", eventID).
		Group("candidate_id").
		Scan(&results).Error

	if err != nil {
		return nil, err
	}

	resultMap := make(map[uuid.UUID]int64)
	for _, r := range results {
		resultMap[r.CandidateID] = r.VoteCount
	}

	return resultMap, nil
}