import { strict as assert } from 'node:assert';
import { describe, it } from 'node:test';
import type { Contract, SlaTerm } from '@pig/db';
import {
  renewalAlarm,
  resolveContractPrecedence,
  validateParentRelationship,
} from '../src/services/contracts';

function contract(overrides: Partial<Contract>): Contract {
  return {
    id: '10000000-0000-4000-8000-000000000001',
    accountId: '20000000-0000-4000-8000-000000000002',
    type: 'msa',
    status: 'executed',
    side: 'demand',
    title: 'Master agreement',
    externalReference: null,
    demandDealId: null,
    supplyDealId: null,
    capacityCommitmentId: null,
    parentContractId: null,
    contractingPartyName: null,
    takeOrPayFloorPct: null,
    prepaidPct: null,
    terminationTier: null,
    assignableOnDefault: false,
    assignmentDeadlineBusinessDays: null,
    effectiveAt: null,
    expiresAt: null,
    executedAt: null,
    terminatedAt: null,
    isAutoRenew: false,
    noticeDays: null,
    valueCents: null,
    currency: 'USD',
    governingLaw: null,
    documentUrl: null,
    ownerUserId: null,
    notes: null,
    createdAt: new Date('2026-01-01T00:00:00.000Z'),
    updatedAt: new Date('2026-01-01T00:00:00.000Z'),
    ...overrides,
  };
}

function sla(overrides: Partial<SlaTerm>): SlaTerm {
  return {
    id: '30000000-0000-4000-8000-000000000003',
    contractId: '10000000-0000-4000-8000-000000000001',
    kind: 'negotiated',
    uptimeTargetPct: null,
    nodeReplacementHours: null,
    mttrHours: null,
    supportResponseHours: null,
    measurementWindow: 'monthly',
    measurementUnit: 'cluster',
    remedyType: 'service_credit',
    abatementTriggerValue: null,
    abatementTriggerUnit: null,
    claimDeadlineValue: null,
    claimDeadlineUnit: 'days',
    creditExpiryMonths: null,
    isSoleRemedy: true,
    sparePoolObligation: null,
    sparePoolScope: [],
    maintenanceClasses: [],
    reasonableEndeavoursDaysPerYear: null,
    rcaDeliveryHours: null,
    creditSchedule: [],
    creditCapPct: null,
    exclusions: null,
    createdAt: new Date('2026-01-01T00:00:00.000Z'),
    updatedAt: new Date('2026-01-01T00:00:00.000Z'),
    ...overrides,
  };
}

describe('contract precedence', () => {
  it('uses explicit order-form terms before the MSA without copying inherited values', () => {
    const master = contract({ takeOrPayFloorPct: '70.00', prepaidPct: '25.00' });
    const order = contract({
      id: '10000000-0000-4000-8000-000000000004',
      type: 'order_form',
      title: 'Order form',
      parentContractId: master.id,
      takeOrPayFloorPct: '90.00',
    });
    const resolved = resolveContractPrecedence(order.id, [master, order], [
      sla({ uptimeTargetPct: '99.900' }),
    ]);

    const floor = resolved.contract.takeOrPayFloorPct;
    const prepaid = resolved.contract.prepaidPct;
    const uptime = resolved.sla.uptimeTargetPct;
    assert.ok(floor);
    assert.ok(prepaid);
    assert.ok(uptime);

    assert.equal(floor.value, '90.00');
    assert.equal(floor.inherited, false);
    assert.equal(prepaid.value, '25.00');
    assert.equal(prepaid.inherited, true);
    assert.equal(uptime.sourceContractId, master.id);
  });

  it('treats false, zero and an empty list as deliberate child overrides', () => {
    const master = contract({ assignableOnDefault: true });
    const child = contract({
      id: '10000000-0000-4000-8000-000000000004',
      parentContractId: master.id,
      assignableOnDefault: false,
    });
    const resolved = resolveContractPrecedence(child.id, [master, child], [
      sla({ sparePoolScope: ['compute nodes', 'network switches'] }),
      sla({
        id: '30000000-0000-4000-8000-000000000004',
        contractId: child.id,
        reasonableEndeavoursDaysPerYear: 0,
        sparePoolScope: [],
      }),
    ]);

    const assignable = resolved.contract.assignableOnDefault;
    const reasonableEndeavours = resolved.sla.reasonableEndeavoursDaysPerYear;
    const sparePoolScope = resolved.sla.sparePoolScope;
    assert.ok(assignable);
    assert.ok(reasonableEndeavours);
    assert.ok(sparePoolScope);

    assert.equal(assignable.value, false);
    assert.equal(reasonableEndeavours.value, 0);
    assert.deepEqual(sparePoolScope.value, []);
  });
});

describe('contract alarms and hierarchy', () => {
  it('raises the renewal alarm at the negotiated notice deadline, not at expiry', () => {
    const result = renewalAlarm(
      {
        isAutoRenew: true,
        expiresAt: new Date('2026-04-01T00:00:00.000Z'),
        noticeDays: 60,
      },
      new Date('2026-02-15T00:00:00.000Z'),
    );
    assert.equal(result.renewalNoticeAt?.toISOString(), '2026-01-31T00:00:00.000Z');
    assert.equal(result.renewalState, 'due');
  });

  it('rejects cross-account parentage even when both records otherwise look valid', () => {
    const child = contract({ id: '10000000-0000-4000-8000-000000000004' });
    const parent = contract({ accountId: '20000000-0000-4000-8000-000000000009' });
    assert.equal(
      validateParentRelationship(child, parent, []),
      'Parent and child contracts must belong to the same account.',
    );
  });
});
