<template>
  <div class="tx-history">
    <h3 class="tx-history__title">
      Transaction History
      <span class="tx-history__count" v-if="transactions.length">{{ transactions.length }}</span>
    </h3>

    <div v-if="loading" class="tx-history__loading">
      <div class="spinner"></div>
      Loading transactions…
    </div>

    <div v-else-if="error" class="tx-history__error">⚠ {{ error }}</div>

    <div v-else-if="transactions.length === 0" class="tx-history__empty">No transactions found for this address.</div>

    <div v-else class="tx-history__table-wrapper">
      <table class="tx-table">
        <thead>
          <tr>
            <th>Date</th>
            <th>Type</th>
            <th class="text-right">Amount (KRK)</th>
            <th class="text-right">Value</th>
            <th>Tx</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="tx in transactions" :key="tx.id" :class="txRowClass(tx.type)">
            <td class="tx-date">{{ formatDate(tx.timestamp) }}</td>
            <td>
              <span class="tx-type-badge" :class="txTypeClass(tx.type)">
                {{ txTypeLabel(tx.type) }}
              </span>
            </td>
            <td class="text-right mono">{{ formatKrk(tx.tokenAmount) }}</td>
            <td class="text-right mono">
              <template v-if="tx.ethAmount !== '0'">
                <span :title="formatEthCell(tx.ethAmount)">
                  {{ ethUsdPrice ? formatCellUsd(tx.ethAmount) : formatEthCell(tx.ethAmount) }}
                </span>
                <br v-if="ethUsdPrice" />
                <span v-if="ethUsdPrice" class="tx-eth-sub">{{ formatEthCell(tx.ethAmount) }}</span>
              </template>
              <template v-else>—</template>
            </td>
            <td>
              <a :href="explorerTxUrl(tx.txHash)" target="_blank" rel="noopener noreferrer" class="tx-link" :title="tx.txHash">
                {{ shortHash(tx.txHash) }} ↗
              </a>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue';
import { useEthPrice, formatUsd } from '../composables/useEthPrice';

interface Transaction {
  id: string;
  holder: string;
  type: string;
  tokenAmount: string;
  ethAmount: string;
  timestamp: string;
  blockNumber: number;
  txHash: string;
}

const props = defineProps<{
  address: string;
  graphqlUrl?: string;
  typeFilter?: string[];
}>();

const transactions = ref<Transaction[]>([]);
const loading = ref(true);
const error = ref<string | null>(null);

const graphqlUrl = computed(() => props.graphqlUrl || '/api/graphql');

const { ethUsdPrice } = useEthPrice();

async function fetchTransactions(address: string) {
  if (!address) {
    loading.value = false;
    return;
  }
  loading.value = true;
  error.value = null;

  try {
    const hasTypeFilter = props.typeFilter && props.typeFilter.length > 0;
    const query = hasTypeFilter
      ? `query TxHistory($holder: String!, $types: [String]) {
          transactionss(
            where: { holder: $holder, type_in: $types }
            orderBy: "timestamp"
            orderDirection: "desc"
            limit: 50
          ) {
            items {
              id
              holder
              type
              tokenAmount
              ethAmount
              timestamp
              blockNumber
              txHash
            }
          }
        }`
      : `query TxHistory($holder: String!) {
          transactionss(
            where: { holder: $holder }
            orderBy: "timestamp"
            orderDirection: "desc"
            limit: 50
          ) {
            items {
              id
              holder
              type
              tokenAmount
              ethAmount
              timestamp
              blockNumber
              txHash
            }
          }
        }`;

    const variables: Record<string, unknown> = { holder: address.toLowerCase() };
    if (hasTypeFilter) variables.types = props.typeFilter;

    const res = await fetch(graphqlUrl.value, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ query, variables }),
    });

    const data = await res.json();

    if (Array.isArray(data?.errors) && data.errors.length > 0) {
      const msgs = data.errors.map((e: { message?: string }) => e.message ?? 'GraphQL error').join(', ');
      throw new Error(msgs);
    }

    transactions.value = data?.data?.transactionss?.items ?? [];
  } catch (e) {
    // eslint-disable-next-line no-console
    console.error('Failed to fetch transactions:', e);
    error.value = e instanceof Error ? e.message : 'Failed to load transactions';
    transactions.value = [];
  } finally {
    loading.value = false;
  }
}

function weiToEth(raw: string): number {
  try {
    const big = BigInt(raw || '0');
    return Number(big * 10000n / (10n ** 18n)) / 10000;
  } catch {
    return 0;
  }
}

function formatDate(timestamp: string): string {
  const ts = Number(timestamp) * 1000;
  if (!ts) return '—';
  const d = new Date(ts);
  return (
    d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: '2-digit' }) +
    ' ' +
    d.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: false })
  );
}

function formatKrk(raw: string): string {
  try {
    const big = BigInt(raw || '0');
    const val = Number(big * 10000n / (10n ** 18n)) / 10000;
    return val.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 4 });
  } catch {
    return '0.00';
  }
}

function formatEthCell(raw: string): string {
  const eth = weiToEth(raw);
  if (eth === 0) return '0';
  if (eth >= 1) return `${eth.toFixed(2)} ETH`;
  if (eth >= 0.01) return `${eth.toFixed(4)} ETH`;
  if (eth >= 0.0001) return `${eth.toFixed(6)} ETH`;
  return `${eth.toPrecision(4)} ETH`;
}

function formatCellUsd(raw: string): string {
  if (!ethUsdPrice.value) return formatEthCell(raw);
  return formatUsd(weiToEth(raw) * ethUsdPrice.value);
}

function shortHash(hash: string): string {
  if (!hash || hash.length < 12) return hash;
  return `${hash.slice(0, 6)}…${hash.slice(-4)}`;
}

function explorerTxUrl(hash: string): string {
  // Base mainnet explorer; adjust for testnet if needed
  return `https://basescan.org/tx/${hash}`;
}

function txTypeLabel(type: string): string {
  const labels: Record<string, string> = {
    buy: 'Buy',
    sell: 'Sell',
    stake: 'Stake',
    unstake: 'Unstake',
    snatch_in: 'Snatched In',
    snatch_out: 'Snatched Out',
  };
  return labels[type] || type;
}

function txTypeClass(type: string): string {
  if (['buy', 'unstake', 'snatch_in'].includes(type)) return 'tx-type--positive';
  if (['sell', 'snatch_out'].includes(type)) return 'tx-type--negative';
  return 'tx-type--neutral';
}

function txRowClass(type: string): string {
  if (['buy', 'unstake'].includes(type)) return 'tx-row--positive';
  if (['sell', 'snatch_out'].includes(type)) return 'tx-row--negative';
  return '';
}

onMounted(() => fetchTransactions(props.address));
watch(
  () => props.address,
  addr => fetchTransactions(addr)
);
</script>

<style lang="sass" scoped>
.tx-history
  display: flex
  flex-direction: column
  gap: 16px

  &__title
    display: flex
    align-items: center
    gap: 10px
    font-size: 20px
    color: #ffffff
    margin: 0

  &__count
    background: rgba(117, 80, 174, 0.3)
    color: #7550AE
    border-radius: 99px
    padding: 2px 10px
    font-size: 14px
    font-weight: 700

  &__loading
    display: flex
    align-items: center
    gap: 12px
    color: #9A9898
    padding: 24px

  &__error
    background: rgba(248, 113, 113, 0.1)
    border: 1px solid rgba(248, 113, 113, 0.3)
    border-radius: 12px
    padding: 16px
    color: #F87171

  &__empty
    color: #9A9898
    padding: 24px
    text-align: center
    background: #07111B
    border-radius: 12px
    border: 1px solid rgba(255,255,255,0.07)

  &__table-wrapper
    overflow-x: auto
    border-radius: 12px
    border: 1px solid rgba(255,255,255,0.08)

.tx-table
  width: 100%
  border-collapse: collapse
  font-size: 14px

  th
    text-align: left
    padding: 12px 16px
    color: #9A9898
    font-size: 11px
    text-transform: uppercase
    letter-spacing: 1px
    border-bottom: 1px solid rgba(255,255,255,0.08)
    white-space: nowrap

  td
    padding: 12px 16px
    border-bottom: 1px solid rgba(255,255,255,0.04)
    color: #ffffff

  .text-right
    text-align: right

  .mono
    font-family: monospace

.tx-date
  color: #9A9898
  white-space: nowrap
  font-size: 13px

.tx-type-badge
  padding: 3px 10px
  border-radius: 99px
  font-size: 12px
  font-weight: 600
  text-transform: uppercase
  letter-spacing: 0.5px

  &.tx-type--positive
    background: rgba(74, 222, 128, 0.12)
    color: #4ADE80

  &.tx-type--negative
    background: rgba(248, 113, 113, 0.12)
    color: #F87171

  &.tx-type--neutral
    background: rgba(117, 80, 174, 0.15)
    color: #7550AE

.tx-row--positive td
  background: rgba(74, 222, 128, 0.03)

.tx-row--negative td
  background: rgba(248, 113, 113, 0.03)

.tx-link
  color: #7550AE
  text-decoration: none
  font-family: monospace
  font-size: 13px
  white-space: nowrap
  &:hover
    text-decoration: underline

.tx-eth-sub
  font-size: 11px
  color: #9A9898
  font-family: monospace

.spinner
  width: 20px
  height: 20px
  border: 2px solid rgba(117, 80, 174, 0.3)
  border-top-color: #7550AE
  border-radius: 50%
  animation: spin 0.8s linear infinite

@keyframes spin
  to
    transform: rotate(360deg)
</style>
