import type { Transaction, TransactionInternalCall, TransactionTokenTransfer } from '@/services/api/transactions'
import { getGruExplorerMetadata } from '@/services/api/gruExplorerData'

export interface TransactionComplianceFactor {
  label: string
  score: number
  maxScore: number
  summary: string
}

export interface TransactionComplianceAssessment {
  score: number
  grade: string
  summary: string
  factors: TransactionComplianceFactor[]
}

function scoreToGrade(score: number): string {
  if (score >= 90) return 'A'
  if (score >= 80) return 'B'
  if (score >= 70) return 'C'
  if (score >= 60) return 'D'
  return 'E'
}

export function assessTransactionCompliance(input: {
  transaction: Transaction
  internalCalls: TransactionInternalCall[]
  tokenTransfers: TransactionTokenTransfer[]
}): TransactionComplianceAssessment {
  const { transaction, internalCalls, tokenTransfers } = input

  const executionScore = transaction.status === 1 ? 25 : transaction.status === 0 ? 6 : 12
  const decodeScore = transaction.decoded_input?.parameters?.length ? 15 : transaction.method ? 10 : 3
  const traceabilityScore =
    (transaction.from_address ? 5 : 0) +
    (transaction.to_address || transaction.contract_address ? 5 : 0) +
    (transaction.block_number ? 3 : 0) +
    (transaction.created_at ? 2 : 0)

  const gruTransfers = tokenTransfers.filter((transfer) =>
    Boolean(getGruExplorerMetadata({ address: transfer.token_address, symbol: transfer.token_symbol })),
  )
  const x402Transfers = tokenTransfers.filter((transfer) =>
    Boolean(getGruExplorerMetadata({ address: transfer.token_address, symbol: transfer.token_symbol })?.x402Ready),
  )
  const isoTransfers = tokenTransfers.filter((transfer) =>
    Boolean(getGruExplorerMetadata({ address: transfer.token_address, symbol: transfer.token_symbol })?.iso20022Ready),
  )

  const assetPostureScore =
    tokenTransfers.length === 0
      ? 10
      : Math.min(
          20,
          Math.round(
            ((gruTransfers.length * 0.45 + x402Transfers.length * 0.3 + isoTransfers.length * 0.25) / tokenTransfers.length) * 20,
          ),
        )

  const auditRichnessScore = Math.min(
    15,
    (tokenTransfers.length > 0 ? 6 : 0) +
      (internalCalls.length > 0 ? 4 : 0) +
      (transaction.input_data ? 3 : 0) +
      (transaction.decoded_input?.parameters?.length ? 2 : 0),
  )

  const exceptionHygieneScore = transaction.revert_reason ? 0 : transaction.status === 1 ? 10 : 4

  const factors: TransactionComplianceFactor[] = [
    {
      label: 'Execution integrity',
      score: executionScore,
      maxScore: 25,
      summary: transaction.status === 1 ? 'Transaction executed successfully.' : 'Execution failed or remains weakly evidenced.',
    },
    {
      label: 'Decode clarity',
      score: decodeScore,
      maxScore: 15,
      summary:
        transaction.decoded_input?.parameters?.length
          ? 'Decoded method parameters are available.'
          : transaction.method
            ? 'A method label is available, but structured parameters are thin.'
            : 'Method decoding is minimal.',
    },
    {
      label: 'Counterparty traceability',
      score: traceabilityScore,
      maxScore: 15,
      summary: 'Based on visible sender, recipient or created contract, block anchoring, and timestamp context.',
    },
    {
      label: 'Asset posture',
      score: assetPostureScore,
      maxScore: 20,
      summary:
        tokenTransfers.length === 0
          ? 'No token transfers were indexed, so asset-policy scoring stays neutral.'
          : `${gruTransfers.length}/${tokenTransfers.length} transfer assets look GRU-aware, ${x402Transfers.length} look x402-ready, and ${isoTransfers.length} look ISO-20022-aligned.`,
    },
    {
      label: 'Audit richness',
      score: auditRichnessScore,
      maxScore: 15,
      summary: 'Based on token transfers, internal calls, raw input visibility, and decoded input availability.',
    },
    {
      label: 'Exception hygiene',
      score: exceptionHygieneScore,
      maxScore: 10,
      summary: transaction.revert_reason ? 'A revert reason is present, which lowers the evidence score.' : 'No explicit revert reason is present.',
    },
  ]

  const score = factors.reduce((sum, factor) => sum + factor.score, 0)
  const grade = scoreToGrade(score)
  const summary =
    score >= 85
      ? 'Strong explorer-visible evidence with good execution and audit context.'
      : score >= 70
        ? 'Reasonable evidence quality, but some audit or standards signals are missing.'
        : 'Limited evidence quality from the explorer-visible signals alone.'

  return { score, grade, summary, factors }
}
