import { ref, computed, onMounted, onUnmounted, type Ref } from 'vue';
import axios from 'axios';
import { DEFAULT_CHAIN_ID } from '@/config';
import { resolveGraphqlEndpoint, formatGraphqlError } from '@/utils/graphqlRetry';
import { parseTokenAmount } from '@/utils/helper';
import logger from '@/utils/logger';

const GRAPHQL_TIMEOUT_MS = 15_000;
const POLL_INTERVAL_MS = 30_000;

export interface PositionRecord {
  id: string;
  owner: string;
  share: number;
  taxRate: number;
  taxRateIndex: number;
  kraikenDeposit: string;
  stakeDeposit: string;
  taxPaid: string;
  snatched: number;
  status: string;
  creationTime: string;
  lastTaxTime: string;
  closedAt: string | null;
  totalSupplyInit: string;
  totalSupplyEnd: string | null;
  payout: string | null;
}

export interface PositionStats {
  stakeTotalSupply: string;
  outstandingStake: string;
  kraikenTotalSupply: string;
  lastEthReserve: string;
}

export interface ActivePositionShort {
  id: string;
  taxRateIndex: number;
  kraikenDeposit: string;
}

function formatDate(ts: string | null): string {
  if (!ts) return 'N/A';
  try {
    // ts may be seconds (unix) or ms
    const num = Number(ts);
    const ms = num > 1e12 ? num : num * 1000;
    return new Date(ms).toLocaleString('en-US', {
      year: 'numeric',
      month: 'short',
      day: 'numeric',
      hour: '2-digit',
      minute: '2-digit',
    });
  } catch {
    return 'N/A';
  }
}

function durationHuman(fromTs: string | null, toTs: string | null = null): string {
  if (!fromTs) return 'N/A';
  try {
    const from = Number(fromTs) > 1e12 ? Number(fromTs) : Number(fromTs) * 1000;
    const to = toTs ? (Number(toTs) > 1e12 ? Number(toTs) : Number(toTs) * 1000) : Date.now();
    const diffMs = to - from;
    if (diffMs < 0) return 'N/A';
    const totalSec = Math.floor(diffMs / 1000);
    const days = Math.floor(totalSec / 86400);
    const hours = Math.floor((totalSec % 86400) / 3600);
    const mins = Math.floor((totalSec % 3600) / 60);
    const parts: string[] = [];
    if (days > 0) parts.push(`${days}d`);
    if (hours > 0) parts.push(`${hours}h`);
    if (mins > 0 && days === 0) parts.push(`${mins}m`);
    return parts.length ? parts.join(' ') : '<1m';
  } catch {
    return 'N/A';
  }
}

export function usePositionDashboard(positionId: Ref<string>) {
  const position = ref<PositionRecord | null>(null);
  const stats = ref<PositionStats | null>(null);
  const allActivePositions = ref<ActivePositionShort[]>([]);
  const loading = ref(false);
  const error = ref<string | null>(null);
  let pollTimer: ReturnType<typeof setInterval> | null = null;

  async function fetchData() {
    const id = positionId.value;
    if (!id) return;

    loading.value = true;
    error.value = null;

    let endpoint: string;
    try {
      endpoint = resolveGraphqlEndpoint(DEFAULT_CHAIN_ID);
    } catch (err) {
      error.value = err instanceof Error ? err.message : 'GraphQL endpoint not configured';
      loading.value = false;
      return;
    }

    try {
      const res = await axios.post(
        endpoint,
        {
          query: `query PositionDashboard($id: String!) {
            positions(id: $id) {
              id
              owner
              share
              taxRate
              taxRateIndex
              kraikenDeposit
              stakeDeposit
              taxPaid
              snatched
              status
              creationTime
              lastTaxTime
              closedAt
              totalSupplyInit
              totalSupplyEnd
              payout
            }
            statss(where: { id: "0x01" }) {
              items {
                stakeTotalSupply
                outstandingStake
                kraikenTotalSupply
                lastEthReserve
              }
            }
            positionss(where: { status: "Active" }, limit: 1000) {
              items {
                id
                taxRateIndex
                kraikenDeposit
              }
            }
          }`,
          variables: { id },
        },
        { timeout: GRAPHQL_TIMEOUT_MS }
      );

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

      position.value = res.data?.data?.positions ?? null;

      const statsItems = res.data?.data?.statss?.items;
      stats.value = Array.isArray(statsItems) && statsItems.length > 0 ? (statsItems[0] as PositionStats) : null;

      const activeItems = res.data?.data?.positionss?.items;
      allActivePositions.value = Array.isArray(activeItems) ? (activeItems as ActivePositionShort[]) : [];

      logger.info(`PositionDashboard loaded for #${id}`);
    } catch (err) {
      error.value = formatGraphqlError(err);
      logger.info('PositionDashboard fetch error', err);
    } finally {
      loading.value = false;
    }
  }

  // Derived values
  const depositKrk = computed(() => parseTokenAmount(position.value?.kraikenDeposit ?? '0'));
  const taxPaidKrk = computed(() => parseTokenAmount(position.value?.taxPaid ?? '0'));

  const currentValueKrk = computed(() => {
    if (!position.value || !stats.value) return 0;
    const share = Number(position.value.share);
    const outstanding = parseTokenAmount(stats.value.outstandingStake);
    return share * outstanding;
  });

  const netReturnKrk = computed(() => {
    return currentValueKrk.value - depositKrk.value - taxPaidKrk.value;
  });

  const taxRatePercent = computed(() => {
    if (!position.value) return 0;
    return Number(position.value.taxRate) * 100;
  });

  const dailyTaxCost = computed(() => {
    if (!position.value) return 0;
    return (depositKrk.value * Number(position.value.taxRate)) / 365;
  });

  const sharePercent = computed(() => {
    if (!position.value) return 0;
    return Number(position.value.share) * 100;
  });

  const createdFormatted = computed(() => formatDate(position.value?.creationTime ?? null));
  const lastTaxFormatted = computed(() => formatDate(position.value?.lastTaxTime ?? null));
  const closedAtFormatted = computed(() => formatDate(position.value?.closedAt ?? null));

  const timeHeld = computed(() => {
    if (!position.value) return 'N/A';
    return durationHuman(position.value.creationTime, position.value.closedAt ?? null);
  });

  // Snatch risk: count active positions with lower taxRateIndex
  const snatchRisk = computed(() => {
    if (!position.value) return { count: 0, level: 'UNKNOWN', color: '#9A9898' };
    const myIndex = Number(position.value.taxRateIndex);
    const lower = allActivePositions.value.filter(p => Number(p.taxRateIndex) < myIndex).length;
    const total = allActivePositions.value.length;

    let level: string;
    let color: string;
    if (total === 0) {
      level = 'LOW';
      color = '#4ADE80';
    } else {
      const ratio = lower / total;
      if (ratio < 0.33) {
        level = 'LOW';
        color = '#4ADE80';
      } else if (ratio < 0.67) {
        level = 'MEDIUM';
        color = '#FACC15';
      } else {
        level = 'HIGH';
        color = '#F87171';
      }
    }

    return { count: lower, level, color };
  });

  const payoutKrk = computed(() => parseTokenAmount(position.value?.payout ?? '0'));

  const netPnlKrk = computed(() => {
    if (!position.value) return 0;
    return payoutKrk.value - depositKrk.value - taxPaidKrk.value;
  });

  onMounted(async () => {
    await fetchData();
    pollTimer = setInterval(() => void fetchData(), POLL_INTERVAL_MS);
  });

  onUnmounted(() => {
    if (pollTimer) {
      clearInterval(pollTimer);
      pollTimer = null;
    }
  });

  return {
    loading,
    error,
    position,
    stats,
    allActivePositions,
    depositKrk,
    taxPaidKrk,
    currentValueKrk,
    netReturnKrk,
    taxRatePercent,
    dailyTaxCost,
    sharePercent,
    createdFormatted,
    lastTaxFormatted,
    closedAtFormatted,
    timeHeld,
    snatchRisk,
    payoutKrk,
    netPnlKrk,
    refresh: fetchData,
  };
}
