package analytics

import (
	"context"
	"fmt"
	"time"

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

// FlowTracker tracks address-to-address flows
type FlowTracker struct {
	db *pgxpool.Pool
	chainID int
}

// NewFlowTracker creates a new flow tracker
func NewFlowTracker(db *pgxpool.Pool, chainID int) *FlowTracker {
	return &FlowTracker{
		db:      db,
		chainID: chainID,
	}
}

// Flow represents a flow between addresses
type Flow struct {
	From      string
	To        string
	Token     string
	Amount    string
	Count     int
	FirstSeen time.Time
	LastSeen  time.Time
}

// TrackFlow tracks a flow between addresses
func (ft *FlowTracker) TrackFlow(ctx context.Context, from, to, token string, amount string) error {
	query := `
		INSERT INTO analytics_flows (
			chain_id, from_address, to_address, token_contract,
			total_amount, transfer_count, first_seen, last_seen
		) VALUES ($1, $2, $3, $4, $5, 1, NOW(), NOW())
		ON CONFLICT (chain_id, from_address, to_address, token_contract) DO UPDATE SET
			total_amount = analytics_flows.total_amount + $5::numeric,
			transfer_count = analytics_flows.transfer_count + 1,
			last_seen = NOW(),
			updated_at = NOW()
	`

	_, err := ft.db.Exec(ctx, query, ft.chainID, from, to, token, amount)
	if err != nil {
		return fmt.Errorf("failed to track flow: %w", err)
	}

	return nil
}

// GetFlows gets flows matching criteria
func (ft *FlowTracker) GetFlows(ctx context.Context, from, to, token string, startDate, endDate *time.Time, limit int) ([]Flow, error) {
	query := `
		SELECT from_address, to_address, token_contract, total_amount, transfer_count, first_seen, last_seen
		FROM analytics_flows
		WHERE chain_id = $1
	`

	args := []interface{}{ft.chainID}
	argIndex := 2

	if from != "" {
		query += fmt.Sprintf(" AND from_address = $%d", argIndex)
		args = append(args, from)
		argIndex++
	}

	if to != "" {
		query += fmt.Sprintf(" AND to_address = $%d", argIndex)
		args = append(args, to)
		argIndex++
	}

	if token != "" {
		query += fmt.Sprintf(" AND token_contract = $%d", argIndex)
		args = append(args, token)
		argIndex++
	}

	if startDate != nil {
		query += fmt.Sprintf(" AND last_seen >= $%d", argIndex)
		args = append(args, *startDate)
		argIndex++
	}

	if endDate != nil {
		query += fmt.Sprintf(" AND last_seen <= $%d", argIndex)
		args = append(args, *endDate)
		argIndex++
	}

	query += " ORDER BY last_seen DESC LIMIT $" + fmt.Sprintf("%d", argIndex)
	args = append(args, limit)

	rows, err := ft.db.Query(ctx, query, args...)
	if err != nil {
		return nil, fmt.Errorf("failed to query flows: %w", err)
	}
	defer rows.Close()

	flows := []Flow{}
	for rows.Next() {
		var f Flow
		if err := rows.Scan(&f.From, &f.To, &f.Token, &f.Amount, &f.Count, &f.FirstSeen, &f.LastSeen); err != nil {
			continue
		}
		flows = append(flows, f)
	}

	return flows, nil
}

