package repository

import (
	"github.com/zs/InsightReply/internal/model"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
)

type TweetRepository struct {
	db *gorm.DB
}

func NewTweetRepository(db *gorm.DB) *TweetRepository {
	return &TweetRepository{db: db}
}

// Upsert intelligently inserts a new tweet or updates an existing one.
// Crucially, on conflict, it dynamically calculates the 'heat_score' by 
// comparing the new metrics against the old metrics currently in the database.
func (r *TweetRepository) Upsert(tweet *model.Tweet) error {
	// For new tweets being inserted, their base heat score evaluates to their current absolute metrics.
	// For existing tweets, we calculate the delta and add it to their existing heat score.
	tweet.HeatScore = float64(tweet.LikeCount*1 + tweet.RetweetCount*2 + tweet.ReplyCount*3)

	err := r.db.Clauses(clause.OnConflict{
		Columns: []clause.Column{{Name: "x_tweet_id"}},
		DoUpdates: clause.Assignments(map[string]interface{}{
			"author_id":       clause.Column{Table: "excluded", Name: "author_id"},
			"author_handle":   clause.Column{Table: "excluded", Name: "author_handle"},
			"content":         clause.Column{Table: "excluded", Name: "content"},
			"posted_at":       clause.Column{Table: "excluded", Name: "posted_at"},
			"last_crawled_at": clause.Column{Table: "excluded", Name: "last_crawled_at"},
			"like_count":      clause.Column{Table: "excluded", Name: "like_count"},
			"retweet_count":   clause.Column{Table: "excluded", Name: "retweet_count"},
			"reply_count":     clause.Column{Table: "excluded", Name: "reply_count"},
			// Calculate delta only if the old values exist and are lower than the new values (to prevent negative spikes from X UI glitches). 
			// heatTracker = old.heat_score + MAX(0, new.like - old.like)*1 + MAX(0, new.rt - old.rt)*2 + MAX(0, new.reply - old.reply)*3
			"heat_score": gorm.Expr("tweets.heat_score + GREATEST(0, EXCLUDED.like_count - tweets.like_count) * 1.0 + GREATEST(0, EXCLUDED.retweet_count - tweets.retweet_count) * 2.0 + GREATEST(0, EXCLUDED.reply_count - tweets.reply_count) * 3.0"),
			
			// Smart Crawling logic: If heat score breaches threshold (e.g. 50), promote to high. If old & cold, demote.
			"crawl_queue": gorm.Expr(`
				CASE 
					WHEN tweets.heat_score + GREATEST(0, EXCLUDED.like_count - tweets.like_count) * 1.0 + GREATEST(0, EXCLUDED.retweet_count - tweets.retweet_count) * 2.0 + GREATEST(0, EXCLUDED.reply_count - tweets.reply_count) * 3.0 > 50 THEN 'high'
					WHEN EXCLUDED.last_crawled_at - tweets.posted_at > INTERVAL '7 days' THEN 'low'
					ELSE 'normal'
				END
			`),
		}),
	}).Create(tweet).Error

	return err
}

// GetTopHeatingTweets returns unprocessed tweets ordered by their generated heat score
func (r *TweetRepository) GetTopHeatingTweets(limit int) ([]model.Tweet, error) {
	var tweets []model.Tweet
	err := r.db.Where("is_processed = ?", false).Order("heat_score desc").Limit(limit).Find(&tweets).Error
	return tweets, err
}

// MarkAsProcessed tags a tweet so we don't present it to the user repeatedly
func (r *TweetRepository) MarkAsProcessed(id string) error {
	return r.db.Model(&model.Tweet{}).Where("id = ?", id).Update("is_processed", true).Error
}

// SearchTweets allows dynamic multi-rule filtering
func (r *TweetRepository) SearchTweets(keyword, handle string, limit int) ([]model.Tweet, error) {
	var tweets []model.Tweet
	query := r.db.Model(&model.Tweet{})

	if keyword != "" {
		// PostgreSQL ILIKE for case-insensitive keyword searching
		query = query.Where("content ILIKE ?", "%"+keyword+"%")
	}

	if handle != "" {
		query = query.Where("author_handle = ?", handle)
	}

	err := query.Order("heat_score desc, posted_at desc").Limit(limit).Find(&tweets).Error
	return tweets, err
}
