package repository

import (
	"context"
	"fmt"
	"math"
	"time"

	dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"

	// "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
	"github.com/jackc/pgx/v5/pgtype"
)

func (s *Store) SaveEvent(ctx context.Context, e domain.Event) error {
	parsedTime, err := time.Parse(time.RFC3339, e.StartTime)
	if err != nil {
		return err
	}

	return s.queries.InsertEvent(ctx, dbgen.InsertEventParams{
		ID:           e.ID,
		SportID:      pgtype.Int4{Int32: e.SportID, Valid: true},
		MatchName:    pgtype.Text{String: e.MatchName, Valid: true},
		HomeTeam:     pgtype.Text{String: e.HomeTeam, Valid: true},
		AwayTeam:     pgtype.Text{String: e.AwayTeam, Valid: true},
		HomeTeamID:   pgtype.Int4{Int32: e.HomeTeamID, Valid: true},
		AwayTeamID:   pgtype.Int4{Int32: e.AwayTeamID, Valid: true},
		HomeKitImage: pgtype.Text{String: e.HomeKitImage, Valid: true},
		AwayKitImage: pgtype.Text{String: e.AwayKitImage, Valid: true},
		LeagueID:     pgtype.Int4{Int32: e.LeagueID, Valid: true},
		LeagueName:   pgtype.Text{String: e.LeagueName, Valid: true},
		LeagueCc:     pgtype.Text{String: e.LeagueCC, Valid: true},
		StartTime:    pgtype.Timestamp{Time: parsedTime, Valid: true},
		Score:        pgtype.Text{String: e.Score, Valid: true},
		MatchMinute:  pgtype.Int4{Int32: int32(e.MatchMinute), Valid: true},
		TimerStatus:  pgtype.Text{String: e.TimerStatus, Valid: true},
		AddedTime:    pgtype.Int4{Int32: int32(e.AddedTime), Valid: true},
		MatchPeriod:  pgtype.Int4{Int32: int32(e.MatchPeriod), Valid: true},
		IsLive:       pgtype.Bool{Bool: e.IsLive, Valid: true},
		Status:       pgtype.Text{String: e.Status, Valid: true},
		Source:       pgtype.Text{String: e.Source, Valid: true},
	})
}
func (s *Store) SaveUpcomingEvent(ctx context.Context, e domain.UpcomingEvent) error {
	return s.queries.InsertUpcomingEvent(ctx, dbgen.InsertUpcomingEventParams{
		ID:           e.ID,
		SportID:      pgtype.Int4{Int32: e.SportID, Valid: true},
		MatchName:    pgtype.Text{String: e.MatchName, Valid: true},
		HomeTeam:     pgtype.Text{String: e.HomeTeam, Valid: true},
		AwayTeam:     pgtype.Text{String: e.AwayTeam, Valid: true},
		HomeTeamID:   pgtype.Int4{Int32: e.HomeTeamID, Valid: true},
		AwayTeamID:   pgtype.Int4{Int32: e.AwayTeamID, Valid: true},
		HomeKitImage: pgtype.Text{String: e.HomeKitImage, Valid: true},
		AwayKitImage: pgtype.Text{String: e.AwayKitImage, Valid: true},
		LeagueID:     pgtype.Int4{Int32: e.LeagueID, Valid: true},
		LeagueName:   pgtype.Text{String: e.LeagueName, Valid: true},
		LeagueCc:     pgtype.Text{String: e.LeagueCC, Valid: true},
		StartTime:    pgtype.Timestamp{Time: e.StartTime, Valid: true},
		Source:       pgtype.Text{String: e.Source, Valid: true},
	})
}

func (s *Store) GetLiveEventIDs(ctx context.Context) ([]string, error) {
	return s.queries.ListLiveEvents(ctx)
}
func (s *Store) GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error) {
	events, err := s.queries.GetAllUpcomingEvents(ctx)
	if err != nil {
		return nil, err
	}

	upcomingEvents := make([]domain.UpcomingEvent, len(events))
	for i, e := range events {
		upcomingEvents[i] = domain.UpcomingEvent{
			ID:           e.ID,
			SportID:      e.SportID.Int32,
			MatchName:    e.MatchName.String,
			HomeTeam:     e.HomeTeam.String,
			AwayTeam:     e.AwayTeam.String,
			HomeTeamID:   e.HomeTeamID.Int32,
			AwayTeamID:   e.AwayTeamID.Int32,
			HomeKitImage: e.HomeKitImage.String,
			AwayKitImage: e.AwayKitImage.String,
			LeagueID:     e.LeagueID.Int32,
			LeagueName:   e.LeagueName.String,
			LeagueCC:     e.LeagueCc.String,
			StartTime:    e.StartTime.Time.UTC(),
			Source:       e.Source.String,
			Status:       domain.EventStatus(e.Status.String),
		}
	}
	return upcomingEvents, nil
}

func (s *Store) GetExpiredUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.UpcomingEvent, error) {
	events, err := s.queries.GetExpiredUpcomingEvents(ctx, pgtype.Text{
		String: filter.MatchStatus.Value,
		Valid:  filter.MatchStatus.Valid,
	})
	if err != nil {
		return nil, err
	}

	upcomingEvents := make([]domain.UpcomingEvent, len(events))
	for i, e := range events {
		upcomingEvents[i] = domain.UpcomingEvent{
			ID:           e.ID,
			SportID:      e.SportID.Int32,
			MatchName:    e.MatchName.String,
			HomeTeam:     e.HomeTeam.String,
			AwayTeam:     e.AwayTeam.String,
			HomeTeamID:   e.HomeTeamID.Int32,
			AwayTeamID:   e.AwayTeamID.Int32,
			HomeKitImage: e.HomeKitImage.String,
			AwayKitImage: e.AwayKitImage.String,
			LeagueID:     e.LeagueID.Int32,
			LeagueName:   e.LeagueName.String,
			LeagueCC:     e.LeagueCc.String,
			StartTime:    e.StartTime.Time.UTC(),
			Source:       e.Source.String,
			Status:       domain.EventStatus(e.Status.String),
		}
	}
	return upcomingEvents, nil
}

func (s *Store) GetPaginatedUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.UpcomingEvent, int64, error) {

	events, err := s.queries.GetPaginatedUpcomingEvents(ctx, dbgen.GetPaginatedUpcomingEventsParams{
		LeagueID: pgtype.Int4{
			Int32: int32(filter.LeagueID.Value),
			Valid: filter.LeagueID.Valid,
		},
		SportID: pgtype.Int4{
			Int32: int32(filter.SportID.Value),
			Valid: filter.SportID.Valid,
		},
		Limit: pgtype.Int4{
			Int32: int32(filter.Limit.Value),
			Valid: filter.Limit.Valid,
		},
		Offset: pgtype.Int4{
			Int32: int32(filter.Offset.Value * filter.Limit.Value),
			Valid: filter.Offset.Valid,
		},
		FirstStartTime: pgtype.Timestamp{
			Time:  filter.FirstStartTime.Value.UTC(),
			Valid: filter.FirstStartTime.Valid,
		},
		LastStartTime: pgtype.Timestamp{
			Time:  filter.LastStartTime.Value.UTC(),
			Valid: filter.LastStartTime.Valid,
		},
		CountryCode: pgtype.Text{
			String: filter.CountryCode.Value,
			Valid:  filter.CountryCode.Valid,
		},
	})

	if err != nil {
		return nil, 0, err
	}
	upcomingEvents := make([]domain.UpcomingEvent, len(events))
	for i, e := range events {
		upcomingEvents[i] = domain.UpcomingEvent{
			ID:           e.ID,
			SportID:      e.SportID.Int32,
			MatchName:    e.MatchName.String,
			HomeTeam:     e.HomeTeam.String,
			AwayTeam:     e.AwayTeam.String,
			HomeTeamID:   e.HomeTeamID.Int32,
			AwayTeamID:   e.AwayTeamID.Int32,
			HomeKitImage: e.HomeKitImage.String,
			AwayKitImage: e.AwayKitImage.String,
			LeagueID:     e.LeagueID.Int32,
			LeagueName:   e.LeagueName.String,
			LeagueCC:     e.LeagueCc.String,
			StartTime:    e.StartTime.Time.UTC(),
			Source:       e.Source.String,
			Status:       domain.EventStatus(e.Status.String),
		}
	}
	totalCount, err := s.queries.GetTotalEvents(ctx, dbgen.GetTotalEventsParams{
		LeagueID: pgtype.Int4{
			Int32: int32(filter.LeagueID.Value),
			Valid: filter.LeagueID.Valid,
		},
		SportID: pgtype.Int4{
			Int32: int32(filter.SportID.Value),
			Valid: filter.SportID.Valid,
		},
		FirstStartTime: pgtype.Timestamp{
			Time:  filter.FirstStartTime.Value.UTC(),
			Valid: filter.FirstStartTime.Valid,
		},
		LastStartTime: pgtype.Timestamp{
			Time:  filter.LastStartTime.Value.UTC(),
			Valid: filter.LastStartTime.Valid,
		},
		CountryCode: pgtype.Text{
			String: filter.CountryCode.Value,
			Valid:  filter.CountryCode.Valid,
		},
	})
	if err != nil {
		return nil, 0, err
	}

	numberOfPages := math.Ceil(float64(totalCount) / float64(filter.Limit.Value))
	return upcomingEvents, int64(numberOfPages), nil
}
func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error) {
	event, err := s.queries.GetUpcomingByID(ctx, ID)
	if err != nil {
		return domain.UpcomingEvent{}, err
	}

	return domain.UpcomingEvent{
		ID:           event.ID,
		SportID:      event.SportID.Int32,
		MatchName:    event.MatchName.String,
		HomeTeam:     event.HomeTeam.String,
		AwayTeam:     event.AwayTeam.String,
		HomeTeamID:   event.HomeTeamID.Int32,
		AwayTeamID:   event.AwayTeamID.Int32,
		HomeKitImage: event.HomeKitImage.String,
		AwayKitImage: event.AwayKitImage.String,
		LeagueID:     event.LeagueID.Int32,
		LeagueName:   event.LeagueName.String,
		LeagueCC:     event.LeagueCc.String,
		StartTime:    event.StartTime.Time.UTC(),
		Source:       event.Source.String,
		Status:       domain.EventStatus(event.Status.String),
	}, nil
}
func (s *Store) UpdateFinalScore(ctx context.Context, eventID, fullScore string, status domain.EventStatus) error {
	params := dbgen.UpdateMatchResultParams{
		Score:  pgtype.Text{String: fullScore, Valid: true},
		Status: pgtype.Text{String: string(status), Valid: true},
		ID:     eventID,
	}

	err := s.queries.UpdateMatchResult(ctx, params)
	if err != nil {
		return fmt.Errorf("failed to update final score for event %s: %w", eventID, err)
	}

	return nil
}

func (s *Store) UpdateEventStatus(ctx context.Context, eventID string, status domain.EventStatus) error {
	params := dbgen.UpdateMatchResultParams{
		Status: pgtype.Text{
			String: string(status),
			Valid:  true,
		},
		ID: eventID,
	}

	err := s.queries.UpdateMatchResult(ctx, params)

	if err != nil {
		return err
	}
	return nil

}

func (s *Store) DeleteEvent(ctx context.Context, eventID string) error {
	err := s.queries.DeleteEvent(ctx, eventID)
	if err != nil {
		return err
	}
	return nil
}
