import { onchainTable, index } from 'ponder';
import { TAX_RATE_OPTIONS } from 'kraiken-lib/taxRates';

export const HOURS_IN_RING_BUFFER = 168; // 7 days * 24 hours
const RING_BUFFER_SEGMENTS = 4; // ethReserve, minted, burned, holderCount

export const stackMeta = onchainTable('stackMeta', t => ({
  id: t.text().primaryKey(),
  contractVersion: t
    .integer()
    .notNull()
    .$default(() => 0),
  ponderVersion: t
    .text()
    .notNull()
    .$default(() => 'unknown'),
  kraikenLibVersion: t
    .integer()
    .notNull()
    .$default(() => 0),
  updatedAt: t
    .bigint()
    .notNull()
    .$default(() => 0n),
}));

// Global protocol stats - singleton with id "0x01"
export const stats = onchainTable('stats', t => ({
  id: t.text().primaryKey(), // Always "0x01"
  kraikenTotalSupply: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  stakeTotalSupply: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  outstandingStake: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  positionsUpdatedAt: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  minStake: t
    .bigint()
    .notNull()
    .$default(() => 0n),

  // Totals
  totalMinted: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  totalBurned: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  totalTaxPaid: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  // Rolling windows - calculated from ring buffer
  mintedLastWeek: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  mintedLastDay: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  mintNextHourProjected: t
    .bigint()
    .notNull()
    .$default(() => 0n),

  burnedLastWeek: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  burnedLastDay: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  burnNextHourProjected: t
    .bigint()
    .notNull()
    .$default(() => 0n),

  taxPaidLastWeek: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  taxPaidLastDay: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  taxPaidNextHourProjected: t
    .bigint()
    .notNull()
    .$default(() => 0n),

  // Hourly ETH reserve snapshots (from ring buffer slot 0)
  ethReserveLastDay: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  ethReserveLastWeek: t
    .bigint()
    .notNull()
    .$default(() => 0n),

  // Net supply change (minted - burned)
  netSupplyChangeDay: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  netSupplyChangeWeek: t
    .bigint()
    .notNull()
    .$default(() => 0n),

  // Ring buffer state (flattened array of length HOURS_IN_RING_BUFFER * 4)
  ringBufferPointer: t
    .integer()
    .notNull()
    .$default(() => 0),
  lastHourlyUpdateTimestamp: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  ringBuffer: t
    .jsonb()
    .$type<string[]>()
    .notNull()
    .$default(() => Array(HOURS_IN_RING_BUFFER * RING_BUFFER_SEGMENTS).fill('0')),

  // LiquidityManager stats
  holderCount: t
    .integer()
    .notNull()
    .$default(() => 0),
  lastRecenterTimestamp: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  lastRecenterTick: t
    .integer()
    .notNull()
    .$default(() => 0),
  recentersLastDay: t
    .integer()
    .notNull()
    .$default(() => 0),
  recentersLastWeek: t
    .integer()
    .notNull()
    .$default(() => 0),
  lastEthReserve: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  lastVwapTick: t
    .integer()
    .notNull()
    .$default(() => 0),

  // 7-day ETH reserve growth metrics
  ethReserve7dAgo: t.bigint(),
  ethReserveGrowthBps: t.integer(),

  // 7-day trading fees earned
  feesEarned7dEth: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  feesEarned7dKrk: t
    .bigint()
    .notNull()
    .$default(() => 0n),
  feesLastUpdated: t.bigint(),

  // Floor price metrics
  floorTick: t.integer(),
  floorPriceWei: t.bigint(),
  currentPriceWei: t.bigint(),
  floorDistanceBps: t.integer(),
}));

// Individual staking positions
export const positions = onchainTable(
  'positions',
  t => ({
    id: t.text().primaryKey(), // Position ID from contract
    owner: t.hex().notNull(),
    share: t.real().notNull(), // Share as decimal (0-1)
    taxRate: t.real().notNull(), // Tax rate as decimal (e.g., 0.01 for 1%) - for display
    taxRateIndex: t.integer().notNull(), // Tax rate index from contract - source of truth
    kraikenDeposit: t.bigint().notNull(),
    stakeDeposit: t.bigint().notNull(),
    taxPaid: t
      .bigint()
      .notNull()
      .$default(() => 0n),
    snatched: t
      .integer()
      .notNull()
      .$default(() => 0),
    creationTime: t.bigint().notNull(),
    lastTaxTime: t.bigint().notNull(),
    status: t
      .text()
      .notNull()
      .$default(() => 'Active'), // "Active" or "Closed"
    createdAt: t.bigint().notNull(),
    closedAt: t.bigint(),
    totalSupplyInit: t.bigint().notNull(),
    totalSupplyEnd: t.bigint(),
    payout: t
      .bigint()
      .notNull()
      .$default(() => 0n),
  }),
  table => ({
    ownerIdx: index().on(table.owner),
    statusIdx: index().on(table.status),
    taxRateIndexIdx: index().on(table.taxRateIndex),
  })
);

// Export decimal values for backward compatibility in event handlers
// Maps index → decimal (e.g., TAX_RATES[0] = 0.01 for 1% yearly)
export const TAX_RATES = TAX_RATE_OPTIONS.map(opt => opt.decimal);

// Recenters - track LiquidityManager recenter events
export const recenters = onchainTable('recenters', t => ({
  id: t.text().primaryKey(), // block_logIndex format
  timestamp: t.bigint().notNull(),
  currentTick: t.integer().notNull(),
  isUp: t.boolean().notNull(),
  ethBalance: t.bigint(), // nullable - only from Scarcity/Abundance events
  outstandingSupply: t.bigint(), // nullable
  vwapTick: t.integer(), // nullable
}));

// Holders - track Kraiken token holders with cost basis for P&L
export const holders = onchainTable(
  'holders',
  t => ({
    address: t.hex().primaryKey(),
    balance: t.bigint().notNull(),
    // Cost basis tracking (updated on swaps only, not wallet-to-wallet transfers)
    totalEthSpent: t
      .bigint()
      .notNull()
      .$default(() => 0n), // cumulative ETH spent buying KRK
    totalTokensAcquired: t
      .bigint()
      .notNull()
      .$default(() => 0n), // cumulative KRK received from buys
  }),
  table => ({
    addressIdx: index().on(table.address),
  })
);

// Transaction history for wallet dashboard
export const transactions = onchainTable(
  'transactions',
  t => ({
    id: t.text().primaryKey(), // txHash-logIndex
    holder: t.hex().notNull(),
    type: t.text().notNull(), // "buy" | "sell" | "stake" | "unstake" | "snatch_in" | "snatch_out"
    tokenAmount: t.bigint().notNull(),
    ethAmount: t
      .bigint()
      .notNull()
      .$default(() => 0n),
    timestamp: t.bigint().notNull(),
    blockNumber: t.integer().notNull(),
    txHash: t.hex().notNull(),
  }),
  table => ({
    holderIdx: index().on(table.holder),
    timestampIdx: index().on(table.timestamp),
  })
);

// Helper constants
export const STATS_ID = '0x01';
export const SECONDS_IN_HOUR = 3600;
