import { parseArticleBody, interpolateTemplateText } from './contract-article.util';
import { ContractRendererService } from './contract-renderer.service';
import { getTemplateMeta } from './contract-template.registry';
import type { ContractViewModel } from './contract-view-model.builder';

describe('parseArticleBody', () => {
  it('numbers each non-empty line as a clause', () => {
    const parsed = parseArticleBody('First clause.\nSecond clause.\n\nThird clause.');
    expect(parsed.paragraph).toBeUndefined();
    expect(parsed.clauses.map((c) => c.text)).toEqual([
      'First clause.',
      'Second clause.',
      'Third clause.',
    ]);
  });

  it('nests "- " lines as bullets under the previous clause', () => {
    const parsed = parseArticleBody('Rates are:\n- USD 10 per ton\n- USD 20 per wagon\nPayment in advance.');
    expect(parsed.clauses).toHaveLength(2);
    expect(parsed.clauses[0].bullets).toEqual(['USD 10 per ton', 'USD 20 per wagon']);
    expect(parsed.clauses[1].text).toBe('Payment in advance.');
  });

  it('renders a single bare line as a paragraph', () => {
    const parsed = parseArticleBody('This Agreement becomes effective when signed.');
    expect(parsed.paragraph).toBe('This Agreement becomes effective when signed.');
    expect(parsed.clauses).toEqual([]);
  });

  it('nests numbered sub-clauses by their outline token and renumbers sequentially', () => {
    const parsed = parseArticleBody(
      '1. Scope\n5.1 Rail transport\n1.1.1 Wagon supply\n2. Payment',
    );
    expect(parsed.clauses.map((c) => [c.number, c.depth, c.text])).toEqual([
      ['1', 1, 'Scope'],
      ['1.1', 2, 'Rail transport'],
      ['1.1.1', 3, 'Wagon supply'],
      ['2', 1, 'Payment'],
    ]);
  });

  it('clamps a sub-clause with no open parent to the next available level', () => {
    const parsed = parseArticleBody('1.1.1 Orphan sub-clause\nSecond clause.');
    expect(parsed.clauses.map((c) => [c.number, c.depth])).toEqual([
      ['1', 1],
      ['2', 1],
    ]);
  });

  it('leaves prose that merely starts with a number un-tokenized', () => {
    const parsed = parseArticleBody('10 tons is the minimum load.\nPayment in advance.');
    expect(parsed.clauses.map((c) => c.text)).toEqual([
      '10 tons is the minimum load.',
      'Payment in advance.',
    ]);
  });

  it('keeps a single explicitly numbered line as a clause, not a paragraph', () => {
    const parsed = parseArticleBody('1. Only clause.');
    expect(parsed.paragraph).toBeUndefined();
    expect(parsed.clauses.map((c) => [c.number, c.text])).toEqual([['1', 'Only clause.']]);
  });
});

describe('interpolateTemplateText', () => {
  it('fills placeholders from the view model', () => {
    expect(
      interpolateTemplateText('Valid until August 31, {{contractYear}}.', {
        contractYear: 2026,
      }),
    ).toBe('Valid until August 31, 2026.');
  });

  it('falls back to raw text on malformed placeholders', () => {
    expect(interpolateTemplateText('Broken {{#if}} tag', {})).toBe('Broken {{#if}} tag');
  });
});

describe('dynamic template rendering (edr-dynamic.hbs)', () => {
  const renderer = new ContractRendererService();
  renderer.onModuleInit();

  function dynamicView(): ContractViewModel {
    const meta = getTemplateMeta('IMP_BULK_USD_FORWARDING');
    return {
      bookingId: 'test-id',
      reference: 'EDR/CT/2026/0042',
      status: 'CONTRACT_READY',
      templateKey: 'IMP_BULK_USD_FORWARDING',
      template: { ...meta, title: 'Bulk Import Contract', templateFile: 'edr-dynamic.hbs' },
      contractDate: '1 January 2026',
      contractYear: 2026,
      client: {
        companyName: 'Abyssinia Trading PLC',
        companyAddress: 'Bole Sub-city, Addis Ababa',
        companyLocation: 'Ethiopia',
        phone: '+251900000000',
        email: 'test@example.com',
        tinNumber: '1234567890',
        vatNumber: 'VAT-001',
        fanNumber: 'FAN-001',
        businessLicense: 'BL-001',
      },
      provider: {
        name: 'Ethio-Djibouti Standard Gauge Railway Share Company',
        address: 'Nifas Silk Lafto Sub City, Addis Ababa, Ethiopia',
        phone: '+251 11 872 0000',
        email: 'info@edr.gov.et',
        tinNumber: '—',
      },
      schedule: {
        originLabel: 'Nagad',
        destinationLabel: 'Galaan Multipurpose Port',
        tradeDirection: 'IMPORT',
        freightType: 'BULK',
        serviceType: 'Rail + clearance',
        scheduledDate: '—',
        contractType: 'GENERAL',
        cargoDescription: 'Steel billets',
        totalWeightVgm: '—',
        equipmentReturn: '—',
        hazardousLabel: 'No',
        firstMilePickupAddress: '—',
        lastMileDeliveryAddress: '—',
      },
      pricing: {
        displayMode: 'UNIT_RATES',
        unitRates: [
          { label: 'Rail transport', unitPrice: 59.4, unit: 'ton', currency: 'USD' },
        ],
        currency: 'USD',
        equipmentReturn: '—',
        originLabel: 'Nagad',
        destinationLabel: 'Galaan Multipurpose Port',
      } as unknown as ContractViewModel['pricing'],
      rateSchedule: {
        freightLanes: [
          { route: 'Nagad → Galaan Multipurpose Port', cargo: 'Wheat', currency: 'USD', amount: '100', unit: 'per wagon' },
        ],
        additionalServices: [
          { route: 'First-mile pickup by truck', cargo: '—', currency: 'USD', amount: '50', unit: 'per wagon' },
        ],
        surcharges: [],
        isEmpty: false,
        currencyLabel: 'USD',
      },
      signatures: [],
      canSignCustomer: false,
      canSignStaff: false,
      hasContractDocument: false,
      hasCustomerSignature: false,
      hasStaffSignature: false,
      dynamicTemplate: {
        code: 'IMPORT_BULK',
        name: 'Bulk Import Contract',
        documentTitle: 'Bulk Cargo Transportation and Customs Clearance Services',
        whereasClauses: ['The Client has agreed to engage the Service Provider.'],
        articles: [
          {
            id: 'objective',
            title: 'Objective of the Services',
            body: 'Integrated logistics services including:\n- Rail transport to GMP\n- Customs clearance',
            order: 1,
          },
          {
            id: 'pricing',
            title: 'Contract Price and Payment Terms',
            body: 'Rates are set out in the Rate Schedule below.\nPayments 100% in advance.',
            order: 2,
          },
          {
            id: 'duration',
            title: 'Duration',
            body: 'Valid until August 31, {{contractYear}}.',
            order: 3,
          },
        ],
      },
    };
  }

  it('renders numbered dynamic articles with bullets and interpolation', () => {
    const html = renderer.render(dynamicView());
    expect(html).toContain('Bulk Cargo Transportation and Customs Clearance Services');
    expect(html).toContain('Article 1');
    expect(html).toContain('Objective of the Services');
    expect(html).toContain('Rail transport to GMP');
    expect(html).toContain('Valid until August 31, 2026.');
    expect(html).toContain('Abyssinia Trading PLC');
    expect(html).toContain('Annex A — Commercial Schedule');
    // Greenish theme marker from styles.hbs
    expect(html).toContain('#1b9e7a');
  });

  it('renders the live rate schedule lane under the pricing article', () => {
    const html = renderer.render(dynamicView());
    expect(html).toContain('Rate Schedule');
    // Base freight lane pulled from the rate config
    expect(html).toContain('Nagad → Galaan Multipurpose Port');
    expect(html).toContain('USD 100 per wagon');
    // Additional-service group
    expect(html).toContain('First-mile pickup by truck');
  });

  it('keeps the generic layout when no dynamic template is attached', () => {
    const view = dynamicView();
    delete view.dynamicTemplate;
    view.template = getTemplateMeta('IMP_BULK_USD_FORWARDING');
    const html = renderer.render(view);
    expect(html).toContain('Article 5: Contract Price');
  });
});
