package repository

import (
	"fmt"
	"narasi-ahli-be/app/database"
	"narasi-ahli-be/app/database/entity"
	"narasi-ahli-be/app/module/ebooks/request"
	"narasi-ahli-be/app/module/ebooks/response"
	"narasi-ahli-be/utils/paginator"
	utilSvc "narasi-ahli-be/utils/service"
	"strings"

	"github.com/rs/zerolog"
)

type ebooksRepository struct {
	DB  *database.Database
	Log zerolog.Logger
}

// EbooksRepository define interface of IEbooksRepository
type EbooksRepository interface {
	GetAll(req request.EbooksQueryRequest) (ebooks []*entity.Ebooks, paging paginator.Pagination, err error)
	FindOne(id uint) (ebook *entity.Ebooks, err error)
	FindBySlug(slug string) (ebook *entity.Ebooks, err error)
	Create(ebook *entity.Ebooks) (ebookReturn *entity.Ebooks, err error)
	Update(id uint, ebook *entity.Ebooks) (err error)
	UpdateSkipNull(id uint, ebook *entity.Ebooks) (err error)
	Delete(id uint) (err error)
	UpdateDownloadCount(id uint) (err error)
	UpdatePurchaseCount(id uint) (err error)
	UpdateWishlistCount(id uint) (err error)
	SummaryStats(authorId uint) (ebookSummaryStats *response.EbookSummaryStats, err error)
}

func NewEbooksRepository(db *database.Database, log zerolog.Logger) EbooksRepository {
	return &ebooksRepository{
		DB:  db,
		Log: log,
	}
}

// implement interface of IEbooksRepository
func (_i *ebooksRepository) GetAll(req request.EbooksQueryRequest) (ebooks []*entity.Ebooks, paging paginator.Pagination, err error) {
	var count int64

	query := _i.DB.DB.Model(&entity.Ebooks{}).
		Preload("Author").
		Where("ebooks.is_active = ?", true)

	if req.Title != nil && *req.Title != "" {
		title := strings.ToLower(*req.Title)
		query = query.Where("LOWER(ebooks.title) LIKE ?", "%"+strings.ToLower(title)+"%")
	}
	if req.Description != nil && *req.Description != "" {
		description := strings.ToLower(*req.Description)
		query = query.Where("LOWER(ebooks.description) LIKE ?", "%"+strings.ToLower(description)+"%")
	}
	if req.AuthorId != nil {
		query = query.Where("ebooks.author_id = ?", req.AuthorId)
	}
	if req.Category != nil && *req.Category != "" {
		category := strings.ToLower(*req.Category)
		query = query.Where("LOWER(ebooks.category) LIKE ?", "%"+strings.ToLower(category)+"%")
	}
	if req.Tags != nil && *req.Tags != "" {
		tags := strings.ToLower(*req.Tags)
		query = query.Where("LOWER(ebooks.tags) LIKE ?", "%"+strings.ToLower(tags)+"%")
	}
	if req.MinPrice != nil {
		query = query.Where("ebooks.price >= ?", req.MinPrice)
	}
	if req.MaxPrice != nil {
		query = query.Where("ebooks.price <= ?", req.MaxPrice)
	}
	if req.IsPublished != nil {
		query = query.Where("ebooks.is_published = ?", req.IsPublished)
	}
	if req.StatusId != nil {
		query = query.Where("ebooks.status_id = ?", req.StatusId)
	}

	query.Count(&count)

	if req.Pagination.SortBy != "" {
		direction := "ASC"
		if req.Pagination.Sort == "desc" {
			direction = "DESC"
		}
		query.Order(fmt.Sprintf("%s %s", req.Pagination.SortBy, direction))
	} else {
		direction := "DESC"
		sortBy := "ebooks.created_at"
		query.Order(fmt.Sprintf("%s %s", sortBy, direction))
	}

	req.Pagination.Count = count
	req.Pagination = paginator.Paging(req.Pagination)

	err = query.Offset(req.Pagination.Offset).Limit(req.Pagination.Limit).Find(&ebooks).Error
	if err != nil {
		return
	}

	paging = *req.Pagination

	return
}

func (_i *ebooksRepository) FindOne(id uint) (ebook *entity.Ebooks, err error) {
	query := _i.DB.DB.Preload("Author")
	if err := query.First(&ebook, id).Error; err != nil {
		return nil, err
	}

	return ebook, nil
}

func (_i *ebooksRepository) FindBySlug(slug string) (ebook *entity.Ebooks, err error) {
	query := _i.DB.DB.Preload("Author").Where("slug = ?", slug)

	if err := query.First(&ebook).Error; err != nil {
		return nil, err
	}

	return ebook, nil
}

func (_i *ebooksRepository) Create(ebook *entity.Ebooks) (ebookReturn *entity.Ebooks, err error) {
	result := _i.DB.DB.Create(ebook)
	return ebook, result.Error
}

func (_i *ebooksRepository) Update(id uint, ebook *entity.Ebooks) (err error) {
	ebookMap, err := utilSvc.StructToMap(ebook)
	if err != nil {
		return err
	}
	return _i.DB.DB.Model(&entity.Ebooks{}).
		Where(&entity.Ebooks{ID: id}).
		Updates(ebookMap).Error
}

func (_i *ebooksRepository) UpdateSkipNull(id uint, ebook *entity.Ebooks) (err error) {
	return _i.DB.DB.Model(&entity.Ebooks{}).
		Where(&entity.Ebooks{ID: id}).
		Updates(ebook).Error
}

func (_i *ebooksRepository) Delete(id uint) error {
	return _i.DB.DB.Delete(&entity.Ebooks{}, id).Error
}

func (_i *ebooksRepository) UpdateDownloadCount(id uint) (err error) {
	return _i.DB.DB.Model(&entity.Ebooks{}).
		Where("id = ?", id).
		Update("download_count", "download_count + 1").Error
}

func (_i *ebooksRepository) UpdatePurchaseCount(id uint) (err error) {
	return _i.DB.DB.Model(&entity.Ebooks{}).
		Where("id = ?", id).
		Update("purchase_count", "purchase_count + 1").Error
}

func (_i *ebooksRepository) UpdateWishlistCount(id uint) (err error) {
	return _i.DB.DB.Model(&entity.Ebooks{}).
		Where("id = ?", id).
		Update("wishlist_count", "wishlist_count + 1").Error
}

func (_i *ebooksRepository) SummaryStats(authorId uint) (ebookSummaryStats *response.EbookSummaryStats, err error) {
	query := _i.DB.DB.Model(&entity.Ebooks{}).
		Select(
			"COUNT(*) AS total_ebooks, "+
				"COALESCE(SUM(purchase_count), 0) AS total_sales, "+
				"COALESCE(SUM(price * purchase_count), 0) AS total_revenue, "+
				"COALESCE(SUM(download_count), 0) AS total_downloads, "+
				"COALESCE(SUM(wishlist_count), 0) AS total_wishlists, "+
				"COALESCE(AVG(rating), 0) AS average_rating").
		Where("author_id = ?", authorId)

	err = query.Scan(&ebookSummaryStats).Error

	return ebookSummaryStats, err
}
