package bitcoin

import (
	"fmt"
	"sort"
	"time"

	"btcphrasechecker/types"
)

// Analyzer implements the ChainAnalyzer interface for Bitcoin
type Analyzer struct {
	addressCount int
}

// NewAnalyzer creates a new Bitcoin analyzer
func NewAnalyzer(addressCount int) *Analyzer {
	return &Analyzer{
		addressCount: addressCount,
	}
}

// DeriveAddresses derives Bitcoin addresses from seed
func (a *Analyzer) DeriveAddresses(seed []byte, count int) ([]types.AddressInfo, error) {
	return DeriveAddresses(seed, count)
}

// GetAddressInfo fetches address information
func (a *Analyzer) GetAddressInfo(address string) (balance, txCount uint64, received, sent uint64, err error) {
	return GetAddressInfo(address)
}

// GetTransactions fetches transactions for an address
func (a *Analyzer) GetTransactions(address string) ([]types.Transaction, error) {
	return GetTransactions(address)
}

// GetChain returns the chain type
func (a *Analyzer) GetChain() types.Chain {
	return types.ChainBitcoin
}

// AnalyzeWallet performs comprehensive wallet analysis
func AnalyzeWallet(seed []byte, addressCount int, verbose bool) (*types.WalletSummary, error) {
	summary := &types.WalletSummary{
		ActiveAddresses:    make([]types.AddressInfo, 0),
		TransactionHistory: make([]types.TransactionDetail, 0),
	}

	// Derive all addresses
	addresses, err := DeriveAddresses(seed, addressCount)
	if err != nil {
		return nil, err
	}

	if verbose {
		fmt.Println("Bitcoin Wallet Analysis")
		fmt.Println("======================")
		fmt.Println()
	}

	// Check each derivation path
	pathStats := make(map[string]struct {
		count    int
		received uint64
		sent     uint64
	})

	for _, pathInfo := range StandardPaths {
		if verbose {
			fmt.Printf("Checking %s: %s - %s\n", pathInfo.Name, pathInfo.Path, pathInfo.Desc)
			fmt.Println("-----------------------------------------------------------")
		}

		pathAddresses := filterByPath(addresses, pathInfo.Path)

		for _, addr := range pathAddresses {
			balance, txCount, received, sent, err := GetAddressInfo(addr.Address)
			if err != nil {
				continue
			}

			addr.Balance = balance
			addr.TxCount = int(txCount)
			addr.Received = received
			addr.Sent = sent

			if txCount > 0 {
				if verbose {
					fmt.Printf("  %s\n", addr.Address)
					fmt.Printf("    Path: %s\n", addr.Path)
					fmt.Printf("    Balance: %.8f BTC\n", float64(balance)/100000000.0)
					fmt.Printf("    Received: %.8f BTC\n", float64(received)/100000000.0)
					fmt.Printf("    Sent: %.8f BTC\n", float64(sent)/100000000.0)
					fmt.Printf("    Transactions: %d\n", txCount)
				}

				summary.TotalBalance += balance
				summary.TotalReceived += received
				summary.TotalSent += sent
				summary.TotalTxCount += int(txCount)
				summary.ActiveAddresses = append(summary.ActiveAddresses, addr)

				// Update path stats
				ps := pathStats[pathInfo.Path]
				ps.count++
				ps.received += received
				ps.sent += sent
				pathStats[pathInfo.Path] = ps
			}

			// Rate limiting
			time.Sleep(100 * time.Millisecond)
		}

		if verbose {
			fmt.Println()
		}
	}

	return summary, nil
}

// FetchTransactionHistory fetches and processes all transactions for active addresses
func FetchTransactionHistory(summary *types.WalletSummary) error {
	var allTransactions []types.TransactionDetail
	receiveTxMap := make(map[string]bool)
	sendTxMap := make(map[string]bool)

	for _, addr := range summary.ActiveAddresses {
		if addr.TxCount == 0 {
			continue
		}

		txs, err := GetTransactions(addr.Address)
		if err != nil {
			continue
		}

		for _, tx := range txs {
			txType := "self"
			amount := uint64(0)

			if tx.Received > 0 && tx.Sent == 0 {
				txType = "received"
				amount = tx.Received
				receiveTxMap[tx.TxID] = true
			} else if tx.Sent > 0 && tx.Received == 0 {
				txType = "sent"
				amount = tx.Sent
				sendTxMap[tx.TxID] = true
			} else if tx.Received > 0 && tx.Sent > 0 {
				txType = "self"
				amount = tx.Received
			}

			detail := types.TransactionDetail{
				TxID:        tx.TxID,
				Time:        tx.Time,
				BlockHeight: tx.BlockHeight,
				Confirmed:   tx.Confirmed,
				Type:        txType,
				Amount:      amount,
				Address:     addr.Address,
			}

			allTransactions = append(allTransactions, detail)
		}

		// Rate limiting
		time.Sleep(100 * time.Millisecond)
	}

	// Sort by time (oldest first)
	sort.Slice(allTransactions, func(i, j int) bool {
		return allTransactions[i].Time.Before(allTransactions[j].Time)
	})

	// Calculate running balance
	balance := uint64(0)
	for i := range allTransactions {
		tx := &allTransactions[i]
		if tx.Type == "received" {
			balance += tx.Amount
		} else if tx.Type == "sent" {
			if balance >= tx.Amount {
				balance -= tx.Amount
			}
		}
		tx.Balance = balance
	}

	summary.TransactionHistory = allTransactions
	summary.ReceiveTxCount = len(receiveTxMap)
	summary.SendTxCount = len(sendTxMap)

	return nil
}

// filterByPath filters addresses by derivation path prefix
func filterByPath(addresses []types.AddressInfo, pathPrefix string) []types.AddressInfo {
	var filtered []types.AddressInfo
	for _, addr := range addresses {
		if len(addr.Path) >= len(pathPrefix) && addr.Path[:len(pathPrefix)] == pathPrefix {
			filtered = append(filtered, addr)
		}
	}
	return filtered
}
