import { ethers } from 'ethers';
import { V3_ABI_IDENTITIES } from './abi';
import { deepFreeze } from './freeze';
import type {
  Bytes32, RetiredRouteMetadata, RouteMetadata, V3NetworkProfile, V3ReadRoute,
} from './types';

const hashText = (value: string): Bytes32 =>
  ethers.keccak256(ethers.toUtf8Bytes(value)) as Bytes32;

export const ACCOUNTABILITY_RULE_SCHEMA_HASH =
  hashText('Vaultfire.AccountabilityRule.MissedCanonicalDeadline.v1');
export const OBJECTIVE_EVIDENCE_SCHEMA_HASH =
  hashText('Vaultfire.ObjectiveEvidence.CanonicalRecordedAt.v1');
export const PRIVACY_EXCLUSIONS_HASH = hashText(
  'NO_BEHAVIORAL_SCORING|NO_REPUTATION|NO_LOYALTY|NO_FLOURISHING|NO_QUALITY|NO_BELIEF|NO_BIOMETRIC|NO_PROFILING|NO_SURVEILLANCE',
);

const EIP712_DOMAIN_TYPE =
  'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' as const;
const ACCOUNTABILITY_TERMS_TYPE =
  'Terms(uint256 bondId,address aiCompany,address counterparty,uint256 companyStake,address stakeAsset,bytes32 missionHash,bytes32 objectiveBreachRulesHash,uint8 objectiveRuleClass,uint16 objectiveRuleSchemaVersion,bytes32 flourishRewardRulesHash,uint256 rewardProgramId,uint64 activePeriodStart,uint64 activePeriodEnd,uint64 challengeWindow,uint96 nonce,uint256 chainId,string protocolVersion)' as const;
const OBJECTIVE_EVIDENCE_TYPE =
  'ObjectiveEvidence(address bond,uint256 chainId,uint256 bondId,bytes32 termsHash,bytes32 ruleHash,address canonicalSource,bytes32 canonicalSourceId,bytes32 obligationId,uint64 requiredBy,uint64 recordedAt,uint64 observedAt,uint96 nonce,uint64 signatureDeadline)' as const;
const TYPED_RESOLUTION_TYPE =
  'TypedResolution(address bond,uint256 chainId,uint256 bondId,bytes32 termsHash,bytes32 ruleHash,bytes32 evidenceHash,bytes32 challengeHash,bool evidenceValid,uint96 nonce,uint64 deadline)' as const;
const PARTNERSHIP_TERMS_TYPE =
  'Terms(uint256 bondId,address partyA,address partyB,uint256 partyAStake,uint256 partyBStake,address stakeAsset,bytes32 partnershipType,bytes32 breachConditionsHash,uint8 objectiveRuleClass,uint16 objectiveRuleSchemaVersion,bytes32 flourishRewardConditionsHash,uint256 rewardProgramId,uint64 proposalDeadline,uint64 activePeriodStart,uint64 activePeriodEnd,uint64 challengeWindow,uint96 nonce,uint256 chainId,string protocolVersion)' as const;
const MUTUAL_SETTLEMENT_TYPE =
  'MutualSettlement(address bond,uint256 chainId,uint256 bondId,bytes32 termsHash,uint256 partyAAmount,uint256 partyBAmount,uint96 nonce,uint64 deadline)' as const;

export const EIP712_DOMAIN_TYPEHASH = hashText(EIP712_DOMAIN_TYPE);
export const ACCOUNTABILITY_TERMS_TYPEHASH = hashText(ACCOUNTABILITY_TERMS_TYPE);
export const OBJECTIVE_EVIDENCE_TYPEHASH = hashText(OBJECTIVE_EVIDENCE_TYPE);
export const TYPED_RESOLUTION_TYPEHASH = hashText(TYPED_RESOLUTION_TYPE);
export const PARTNERSHIP_TERMS_TYPEHASH = hashText(PARTNERSHIP_TERMS_TYPE);
export const MUTUAL_SETTLEMENT_TYPEHASH = hashText(MUTUAL_SETTLEMENT_TYPE);

const emptyDeployments = (): V3NetworkProfile['deployments'] => ({
  accountabilityBond: {
    address: null,
    abiIdentity: V3_ABI_IDENTITIES.accountabilityBond,
    runtimeCodeHash: null,
  },
  partnershipBond: {
    address: null,
    abiIdentity: V3_ABI_IDENTITIES.partnershipBond,
    runtimeCodeHash: null,
  },
  governance: {
    address: null,
    abiIdentity: V3_ABI_IDENTITIES.governance,
    runtimeCodeHash: null,
  },
  mandateRegistry: {
    address: null,
    abiIdentity: V3_ABI_IDENTITIES.mandateRegistry,
    runtimeCodeHash: null,
  },
});

/** Explicit profiles. Null addresses mean unavailable; no other-version fallback exists. */
export const V3_NETWORK_PROFILES = deepFreeze({
  8453: {
    chainId: 8453,
    name: 'Base',
    status: 'unconfigured',
    deployments: emptyDeployments(),
  },
  84532: {
    chainId: 84532,
    name: 'Base Sepolia',
    status: 'unconfigured',
    deployments: emptyDeployments(),
  },
} satisfies Record<8453 | 84532, V3NetworkProfile>);

const route = (
  name: V3ReadRoute,
  disposition: RouteMetadata['disposition'],
  retirement: RouteMetadata['retirement'] = null,
): RouteMetadata => ({ route: name, disposition, retirement });

export const V3_ROUTE_METADATA = deepFreeze({
  bonds: route('bonds', 'adapter-required'),
  pullCredits: route('pullCredits', 'adapter-required'),
  solvency: route('solvency', 'adapter-required'),
  mandates: route('mandates', 'adapter-required'),
  capabilities: route('capabilities', 'unavailable'),
  taskEscrow: route('taskEscrow', 'retired', {
    retiredAt: '2026-08-25',
    replacement: null,
    reason: 'TaskEscrowV3 is outside the canonical supported Base V3 module closure',
  }),
  governance: route('governance', 'adapter-required'),
  'x402.status': route('x402.status', 'unavailable'),
  'x402.discovery': route('x402.discovery', 'unavailable'),
  'x402.challenge': route('x402.challenge', 'unavailable'),
  'x402.receipt': route('x402.receipt', 'unavailable'),
} satisfies Record<V3ReadRoute, RouteMetadata>);

/** Explicitly records prohibited compatibility routing; neither entry is callable. */
export const V3_RETIRED_ROUTES = deepFreeze({
  latest: {
    route: 'latest',
    disposition: 'retired',
    retirement: {
      retiredAt: '2026-08-22',
      replacement: null,
      reason: 'V3 requires an explicit versioned route',
    },
  },
  v2Fallback: {
    route: 'v2-fallback',
    disposition: 'retired',
    retirement: {
      retiredAt: '2026-08-22',
      replacement: null,
      reason: 'V3 never falls back to V2 behavior or deployments',
    },
  },
} satisfies Record<'latest' | 'v2Fallback', RetiredRouteMetadata>);
