import { existsSync, readFileSync } from 'fs';
import { join } from 'path';
import { ethers } from 'ethers';
import { v3 } from '../src';

const root = join(__dirname, '..');
const reviewed = JSON.parse(readFileSync(join(
  root,
  'tests',
  'fixtures',
  'v3-reviewed-abi-signatures.json',
), 'utf8')).deployments.accountabilityBond;
const artifactRelativePath = reviewed.artifact as string;
const currentArtifactPath = join(root, '..', '..', 'v3-src', 'out', artifactRelativePath);
const snapshotArtifactPath = join(
  root,
  'tests',
  'fixtures',
  'reviewed-artifacts',
  artifactRelativePath.split('/').pop()!,
);
const snapshotArtifact = JSON.parse(readFileSync(snapshotArtifactPath, 'utf8'));
const artifact = JSON.parse(readFileSync(
  existsSync(currentArtifactPath) ? currentArtifactPath : snapshotArtifactPath,
  'utf8',
));

const removedGenericDisputeSignatures = [
  'breachSnapshot(uint256,uint256,bytes32)',
  'attestBreach(uint256,uint256,bytes32,uint96)',
  'challengeSettlement(uint256,uint256)',
  'advanceToFinalizable(uint256)',
  'cancelStalledSettlement(uint256)',
  'resolveChallenge(uint256)',
  'freezeSettlement(uint256,uint96)',
  'settle(uint256)',
  'disputeSubject(uint256)',
  'settlementChallengeContext(uint256)',
  'isAuthorizedChallenger(uint256,address)',
  'authorizedRespondent(uint256,address)',
  'disputePayoutSource(uint256)',
  'disputePayoutCap(uint256)',
  'releaseDisputePayout(uint256,address,uint256)',
] as const;

describe('final AccountabilityBondV3Safe ABI reconciliation', () => {
  it('matches the final 36-function artifact and retires every generic-dispute selector', () => {
    const functions = new ethers.Interface(artifact.abi).fragments
      .filter((fragment): fragment is ethers.FunctionFragment => fragment.type === 'function')
      .map((fragment) => ({
        signature: fragment.format('sighash'),
        stateMutability: fragment.stateMutability,
      }))
      .sort((left, right) =>
        left.signature < right.signature ? -1 : left.signature > right.signature ? 1 : 0);
    const signatures = functions.map((method) => method.signature);
    const snapshotSignatures = new ethers.Interface(snapshotArtifact.abi).fragments
      .filter((fragment): fragment is ethers.FunctionFragment => fragment.type === 'function')
      .map((fragment) => fragment.format('sighash'))
      .sort();

    expect(functions).toHaveLength(36);
    expect(snapshotSignatures).toEqual(signatures);
    expect(reviewed.functions).toEqual(functions);
    expect(signatures).toEqual(expect.arrayContaining([
      'FLOURISHING_NON_CONTROL_BOUNDARY()',
      'advanceObjectiveEvidence(uint256)',
    ]));
    for (const removedSignature of removedGenericDisputeSignatures) {
      expect(signatures).not.toContain(removedSignature);
    }

    const identity = ethers.keccak256(ethers.toUtf8Bytes(signatures.join('\n')));
    expect(identity).toBe('0x0c18d05c868716fad4bfc1fcfad2da51c83f247de06a7e3871dcece768a9526f');
    expect(reviewed.identity).toBe(identity);
    expect(v3.V3_ABI_IDENTITIES.accountabilityBond).toBe(identity);
  });

  it('allows the replacement objective-evidence advance write and no retired selector', () => {
    const writes = v3.V3_WRITE_METHODS.accountabilityBond;
    expect(writes.map((method) => method.signature))
      .toContain('advanceObjectiveEvidence(uint256)');
    for (const removedSignature of removedGenericDisputeSignatures) {
      expect(writes.map((method) => method.signature)).not.toContain(removedSignature);
      expect(writes.map((method) => method.selector))
        .not.toContain(ethers.id(removedSignature).slice(0, 10));
    }
  });
});
