package repositories

import (
	"strings"

	configs "astrology-api/configs"
	storedto "astrology-api/dto/store"
	storemodel "astrology-api/models/usermodel"

	"gorm.io/gorm"
)

type StoreProductRepository struct {
	db *gorm.DB
}

func NewStoreProductRepository() *StoreProductRepository {
	return &StoreProductRepository{
		db: configs.DB,
	}
}

func (r *StoreProductRepository) GetProducts(req storedto.ProductListRequest) (*storedto.ProductListResponse, error) {

	var products []storemodel.AstromallProduct

	query := r.db.Model(&storemodel.AstromallProduct{})

	query = query.Where("isActive = ?", true).
		Where("isDelete = ?", false)

	// Category Filter
	if req.ProductCategoryID > 0 {
		query = query.Where("productCategoryId = ?", req.ProductCategoryID)
	}

	// Search Filter
	if strings.TrimSpace(req.Search) != "" {
		query = query.Where("name LIKE ?", "%"+req.Search+"%")
	}

	// Count
	var totalRecords int64

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

	// Pagination

	if req.FetchRecord > 0 {

		query = query.Offset(req.StartIndex)

		query = query.Limit(req.FetchRecord)

	}

	query = query.Order("id DESC")

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

	response := make([]storedto.ProductResponse, 0)

	for _, product := range products {

		response = append(response, storedto.ProductResponse{

			ID: product.ID,

			Name: product.Name,

			Features: product.Features,

			ProductImage: product.ProductImage,

			ProductCategoryID: product.ProductCategoryID,

			Amount: product.Amount,

			Description: func() string {

				if product.Description == nil {
					return ""
				}
				return *product.Description
			}(),
		})

	}

	return &storedto.ProductListResponse{

		RecordList: response,

		TotalRecords: totalRecords,

		Status: 200,

	}, nil

}

func (r *StoreProductRepository) GetProductByID(req storedto.ProductDetailRequest) (*storedto.ProductDetailResponse, error) {

	var product storemodel.AstromallProduct

	err := r.db.
		Where("id = ?", req.ProductID).
		Where("isActive = ?", true).
		Where("isDelete = ?", false).
		First(&product).Error

	if err != nil {
		return nil, err
	}

	//----------------------------------------
	// Product Attributes
	//----------------------------------------

	var attributes []storemodel.ProductAttribute

	r.db.
		Where("productId = ?", product.ID).
		Where("isActive = ?", true).
		Where("isDelete = ?", false).
		Order("displayOrder ASC").
		Find(&attributes)

	attrResponse := make([]storedto.ProductAttributeResponse, 0)

	for _, attr := range attributes {

		attrResponse = append(attrResponse, storedto.ProductAttributeResponse{
			ID:             attr.ID,
			AttributeName:  attr.AttributeName,
			AttributeValue: attr.AttributeValue,
		})
	}

	//----------------------------------------
	// FAQs
	//----------------------------------------

	var faqs []struct {
		ID       uint
		Question string
		Answer   string
	}

	r.db.
		Table("product_details").
		Select("id, question, answer").
		Where("astromallProductId = ?", product.ID).
		Where("isActive = ?", true).
		Find(&faqs)

	faqResponse := make([]storedto.FAQResponse, 0)

	for _, faq := range faqs {

		faqResponse = append(faqResponse, storedto.FAQResponse{
			ID:       faq.ID,
			Question: faq.Question,
			Answer:   faq.Answer,
		})
	}

	//----------------------------------------
	// Reviews
	//----------------------------------------

	var reviews []struct {
		ID       uint
		Review   string
		Rating   int
		UserName string
		Profile  string
	}

	r.db.
		Table("user_reviews").
		Select(`
			user_reviews.id,
			user_reviews.review,
			user_reviews.rating,
			users.name as userName,
			users.profile
		`).
		Joins("LEFT JOIN users ON users.id = user_reviews.userId").
		Where("astromallProductId = ?", product.ID).
		Scan(&reviews)

	reviewResponse := make([]storedto.ReviewResponse, 0)

	for _, review := range reviews {

		reviewResponse = append(reviewResponse, storedto.ReviewResponse{
			ID:       review.ID,
			UserName: review.UserName,
			Profile:  review.Profile,
			Review:   review.Review,
			Rating:   review.Rating,
		})
	}

	//----------------------------------------
	// Response
	//----------------------------------------

	productDescription := ""
	if product.Description != nil {
		productDescription = *product.Description
	}

	response := &storedto.ProductDetailResponse{

		ID:                product.ID,
		Name:              product.Name,
		Features:          product.Features,
		ProductImage:      product.ProductImage,
		ProductCategoryID: product.ProductCategoryID,
		Amount:            product.Amount,
		Description:       productDescription,

		Attributes: attrResponse,

		FAQs: faqResponse,

		Reviews: reviewResponse,

		Status: 200,
	}

	return response, nil
}


func (r *StoreProductRepository) SearchProducts(req storedto.SearchProductRequest) (*storedto.ProductListResponse, error) {

	var products []storemodel.AstromallProduct

	query := r.db.Model(&storemodel.AstromallProduct{}).
	Joins("LEFT JOIN product_categories ON product_categories.id = astromall_products.productCategoryId").
	Where("astromall_products.isActive = ?", true).
	Where("astromall_products.isDelete = ?", false)

	// Search
	if strings.TrimSpace(req.Search) != "" {

		search := "%" + strings.TrimSpace(req.Search) + "%"

		query = query.Where(`
			astromall_products.name LIKE ?
			OR astromall_products.features LIKE ?
			OR astromall_products.description LIKE ?
			OR product_categories.name LIKE ?
		`,
			search,
			search,
			search,
			search,
		)
	}

	//------------------------------------
	// Total Records
	//------------------------------------

	var totalRecords int64

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

	//------------------------------------
	// Pagination
	//------------------------------------

	if req.FetchRecord > 0 {

		query = query.Offset(req.StartIndex)

		query = query.Limit(req.FetchRecord)

	}

	query = query.Order("astromall_products.id DESC")

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

	response := make([]storedto.ProductResponse, 0)

	for _, product := range products {

		response = append(response, storedto.ProductResponse{

			ID: product.ID,

			Name: product.Name,

			Features: product.Features,

			ProductImage: product.ProductImage,

			ProductCategoryID: product.ProductCategoryID,

			Amount: product.Amount,

			Description: func() string {

				if product.Description == nil {
					return ""
				}
				return *product.Description
			}(),
		})

	}

	return &storedto.ProductListResponse{

		RecordList: response,

		TotalRecords: totalRecords,

		Status: 200,

	}, nil

}


func (r *StoreProductRepository) GetSimilarProducts(req storedto.SimilarProductRequest) (*storedto.ProductListResponse, error) {

	var currentProduct storemodel.AstromallProduct

	err := r.db.
		Select("id, productCategoryId").
		Where("id = ?", req.ProductID).
		First(&currentProduct).Error

	if err != nil {
		return nil, err
	}

	var products []storemodel.AstromallProduct

	query := r.db.Model(&storemodel.AstromallProduct{})

	query = query.
		Where("isActive = ?", true).
		Where("isDelete = ?", false).
		Where("productCategoryId = ?", currentProduct.ProductCategoryID).
		Where("id <> ?", req.ProductID)

	var totalRecords int64

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

	if req.FetchRecord > 0 {
		query = query.Offset(req.StartIndex).
			Limit(req.FetchRecord)
	}

	query = query.Order("id DESC")

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

	response := make([]storedto.ProductResponse, 0)

	for _, product := range products {
		description := ""
		if product.Description != nil {
			description = *product.Description
		}
		response = append(response, storedto.ProductResponse{
			ID:                product.ID,
			Name:              product.Name,
			Features:          product.Features,
			ProductImage:      product.ProductImage,
			ProductCategoryID: product.ProductCategoryID,
			Amount:            product.Amount,
			Description:       description,
		})
	}

	return &storedto.ProductListResponse{
		RecordList:   response,
		TotalRecords: totalRecords,
		Status:       200,
	}, nil
}

func (r *StoreProductRepository) GetProductReviews(req storedto.ProductReviewRequest) (*storedto.ProductReviewResponse, error) {

	type ReviewData struct {
		ID       uint
		Review   string
		Rating   int
		UserName string
		Profile  string
		CreatedAt string
	}

	var reviewRows []ReviewData

	err := r.db.
		Table("user_reviews").
		Select(`
			user_reviews.id,
			user_reviews.review,
			user_reviews.rating,
			DATE_FORMAT(user_reviews.created_at,'%d %b %Y') as createdAt,
			users.name as userName,
			users.profile
		`).
		Joins("LEFT JOIN users ON users.id=user_reviews.userId").
		Where("user_reviews.astromallProductId=?", req.ProductID).
		Order("user_reviews.id DESC").
		Scan(&reviewRows).Error

	if err != nil {
		return nil, err
	}

	reviews := make([]storedto.ReviewResponse, 0)

	for _, item := range reviewRows {

		reviews = append(reviews, storedto.ReviewResponse{

			ID: item.ID,

			UserName: item.UserName,

			Profile: item.Profile,

			Review: item.Review,

			Rating: item.Rating,
		})

	}

	var average float64

	r.db.
		Table("user_reviews").
		Select("IFNULL(ROUND(AVG(rating),1),0)").
		Where("astromallProductId=?", req.ProductID).
		Scan(&average)

	var total int64

	r.db.
		Table("user_reviews").
		Where("astromallProductId=?", req.ProductID).
		Count(&total)

	var five int64
	var four int64
	var three int64
	var two int64
	var one int64

	r.db.Table("user_reviews").
		Where("astromallProductId=?", req.ProductID).
		Where("rating=5").
		Count(&five)

	r.db.Table("user_reviews").
		Where("astromallProductId=?", req.ProductID).
		Where("rating=4").
		Count(&four)

	r.db.Table("user_reviews").
		Where("astromallProductId=?", req.ProductID).
		Where("rating=3").
		Count(&three)

	r.db.Table("user_reviews").
		Where("astromallProductId=?", req.ProductID).
		Where("rating=2").
		Count(&two)

	r.db.Table("user_reviews").
		Where("astromallProductId=?", req.ProductID).
		Where("rating=1").
		Count(&one)

	response := &storedto.ProductReviewResponse{

		AverageRating: average,

		TotalReviews: total,

		Reviews: reviews,

		RatingSummary: storedto.RatingSummary{

			FiveStar: five,

			FourStar: four,

			ThreeStar: three,

			TwoStar: two,

			OneStar: one,
		},

		Status: 200,
	}

	return response, nil
}


func (r *StoreProductRepository) GetProductFAQs(req storedto.ProductFAQRequest) (*storedto.ProductFAQResponse, error) {

	type FAQData struct {
		ID       uint
		Question string
		Answer   string
	}

	var faqRows []FAQData

	err := r.db.
		Table("product_details").
		Select("id, question, answer").
		Where("astromallProductId = ?", req.ProductID).
		Where("isActive = ?", true).
		Order("id ASC").
		Scan(&faqRows).Error

	if err != nil {
		return nil, err
	}

	faqs := make([]storedto.FAQResponse, 0)

	for _, faq := range faqRows {

		faqs = append(faqs, storedto.FAQResponse{
			ID:       faq.ID,
			Question: faq.Question,
			Answer:   faq.Answer,
		})

	}

	return &storedto.ProductFAQResponse{
		FAQs:   faqs,
		Status: 200,
	}, nil
}