package repository

import (
	dbgen "Yimaru-Backend/gen/db"
	"Yimaru-Backend/internal/domain"
	"Yimaru-Backend/internal/ports"
	"context"

	"github.com/jackc/pgx/v5/pgtype"
)

func NewRatingStore(s *Store) ports.RatingStore { return s }

func ratingToDomain(r dbgen.Rating) domain.Rating {
	var review *string
	if r.Review.Valid {
		review = &r.Review.String
	}
	return domain.Rating{
		ID:         r.ID,
		UserID:     r.UserID,
		TargetType: domain.RatingTargetType(r.TargetType),
		TargetID:   r.TargetID,
		Stars:      r.Stars,
		Review:     review,
		CreatedAt:  r.CreatedAt.Time,
		UpdatedAt:  r.UpdatedAt.Time,
	}
}

func (s *Store) UpsertRating(
	ctx context.Context,
	userID int64,
	targetType domain.RatingTargetType,
	targetID int64,
	stars int16,
	review *string,
) (domain.Rating, error) {
	reviewVal := pgtype.Text{Valid: false}
	if review != nil {
		reviewVal = pgtype.Text{String: *review, Valid: true}
	}

	row, err := s.queries.UpsertRating(ctx, dbgen.UpsertRatingParams{
		UserID:     userID,
		TargetType: string(targetType),
		TargetID:   targetID,
		Stars:      stars,
		Review:     reviewVal,
	})
	if err != nil {
		return domain.Rating{}, err
	}

	return ratingToDomain(row), nil
}

func (s *Store) GetRatingByUserAndTarget(
	ctx context.Context,
	userID int64,
	targetType domain.RatingTargetType,
	targetID int64,
) (domain.Rating, error) {
	row, err := s.queries.GetRatingByUserAndTarget(ctx, dbgen.GetRatingByUserAndTargetParams{
		UserID:     userID,
		TargetType: string(targetType),
		TargetID:   targetID,
	})
	if err != nil {
		return domain.Rating{}, err
	}

	return ratingToDomain(row), nil
}

func (s *Store) GetRatingsByTarget(
	ctx context.Context,
	targetType domain.RatingTargetType,
	targetID int64,
	limit int32,
	offset int32,
) ([]domain.Rating, error) {
	rows, err := s.queries.GetRatingsByTarget(ctx, dbgen.GetRatingsByTargetParams{
		TargetType: string(targetType),
		TargetID:   targetID,
		Limit:      pgtype.Int4{Int32: limit, Valid: true},
		Offset:     pgtype.Int4{Int32: offset, Valid: true},
	})
	if err != nil {
		return nil, err
	}

	var ratings []domain.Rating
	for _, row := range rows {
		ratings = append(ratings, ratingToDomain(row))
	}

	return ratings, nil
}

func (s *Store) GetRatingSummary(
	ctx context.Context,
	targetType domain.RatingTargetType,
	targetID int64,
) (domain.RatingSummary, error) {
	row, err := s.queries.GetRatingSummary(ctx, dbgen.GetRatingSummaryParams{
		TargetType: string(targetType),
		TargetID:   targetID,
	})
	if err != nil {
		return domain.RatingSummary{}, err
	}

	return domain.RatingSummary{
		TotalCount:   row.TotalCount,
		AverageStars: row.AverageStars,
	}, nil
}

func (s *Store) GetUserRatings(
	ctx context.Context,
	userID int64,
) ([]domain.Rating, error) {
	rows, err := s.queries.GetUserRatings(ctx, userID)
	if err != nil {
		return nil, err
	}

	var ratings []domain.Rating
	for _, row := range rows {
		ratings = append(ratings, ratingToDomain(row))
	}

	return ratings, nil
}

func (s *Store) DeleteRating(
	ctx context.Context,
	ratingID int64,
	userID int64,
) error {
	return s.queries.DeleteRating(ctx, dbgen.DeleteRatingParams{
		ID:     ratingID,
		UserID: userID,
	})
}
