import { tap, expect } from '@push.rocks/tapbundle';
import * as getInvoices from './assets/getasset.js';
import { XInvoiceEncoder, XInvoiceDecoder } from '../ts/index.js';
import * as tsclass from '@tsclass/tsclass';

// Sample test letter data from our test assets
const testLetterData = getInvoices.letterObjects.letter1.demoLetter;

// Test for XInvoice/XRechnung XML format
tap.test('Generate XInvoice XML from letter data', async () => {
  // Create the encoder
  const encoder = new XInvoiceEncoder();
  
  // Generate XInvoice XML
  const xml = encoder.createXInvoiceXml(testLetterData);
  
  // Verify the XML was created properly
  expect(xml).toBeTypeOf('string');
  expect(xml.length).toBeGreaterThan(100);
  
  // Check for UBL/XInvoice structure
  expect(xml).toInclude('oasis:names:specification:ubl');
  expect(xml).toInclude('Invoice');
  expect(xml).toInclude('cbc:ID');
  expect(xml).toInclude(testLetterData.content.invoiceData.id);
  
  // Check for mandatory XRechnung elements
  expect(xml).toInclude('CustomizationID');
  expect(xml).toInclude('xrechnung');
  expect(xml).toInclude('cbc:UBLVersionID');
  
  console.log('Successfully generated XInvoice XML');
});

// Test for special handling of credit notes
tap.test('Generate XInvoice credit note XML', async () => {
  // Create a modified version of the test letter - change type to credit note
  const creditNoteLetter = {...testLetterData};
  creditNoteLetter.content = {...testLetterData.content};
  creditNoteLetter.content.invoiceData = {...testLetterData.content.invoiceData};
  creditNoteLetter.content.invoiceData.type = 'creditnote';
  creditNoteLetter.content.invoiceData.id = 'CN-' + testLetterData.content.invoiceData.id;
  
  // Create encoder
  const encoder = new XInvoiceEncoder();
  
  // Generate XML for credit note
  const xml = encoder.createXInvoiceXml(creditNoteLetter);
  
  // Check that it's a credit note (type code 381)
  expect(xml).toInclude('cbc:InvoiceTypeCode');
  expect(xml).toInclude('381');
  expect(xml).toInclude(creditNoteLetter.content.invoiceData.id);
  
  console.log('Successfully generated XInvoice credit note XML');
});

// Test decoding XInvoice XML
tap.test('Decode XInvoice XML to structured data', async () => {
  // First, create XML to test with
  const encoder = new XInvoiceEncoder();
  const xml = encoder.createXInvoiceXml(testLetterData);
  
  // Create the decoder
  const decoder = new XInvoiceDecoder(xml);
  
  // Decode back to structured data
  const decodedLetter = await decoder.getLetterData();
  
  // Verify we got a letter back
  expect(decodedLetter).toBeTypeOf('object');
  expect(decodedLetter.content?.invoiceData).toBeDefined();
  
  // Check that essential information was extracted
  expect(decodedLetter.content?.invoiceData?.id).toBeDefined();
  expect(decodedLetter.content?.invoiceData?.billedBy).toBeDefined();
  expect(decodedLetter.content?.invoiceData?.billedTo).toBeDefined();
  
  console.log('Successfully decoded XInvoice XML');
});

// Test namespace handling for UBL
tap.test('Handle UBL namespaces correctly', async () => {
  // Create valid UBL XML with namespaces
  const ublXml = `<?xml version="1.0" encoding="UTF-8"?>
    <Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
      xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
      xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
      <cbc:UBLVersionID>2.1</cbc:UBLVersionID>
      <cbc:ID>${testLetterData.content.invoiceData.id}</cbc:ID>
      <cbc:IssueDate>2023-12-31</cbc:IssueDate>
      <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
      <cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
      <cac:AccountingSupplierParty>
        <cac:Party>
          <cac:PartyName>
            <cbc:Name>${testLetterData.content.invoiceData.billedBy.name}</cbc:Name>
          </cac:PartyName>
        </cac:Party>
      </cac:AccountingSupplierParty>
      <cac:AccountingCustomerParty>
        <cac:Party>
          <cac:PartyName>
            <cbc:Name>${testLetterData.content.invoiceData.billedTo.name}</cbc:Name>
          </cac:PartyName>
        </cac:Party>
      </cac:AccountingCustomerParty>
    </Invoice>`;
  
  // Create decoder for the UBL XML
  const decoder = new XInvoiceDecoder(ublXml);
  
  // Extract the data
  const decodedLetter = await decoder.getLetterData();
  
  // Verify extraction worked with namespaces
  expect(decodedLetter.content?.invoiceData?.id).toBeDefined();
  expect(decodedLetter.content?.invoiceData?.billedBy.name).toBeDefined();
  
  console.log('Successfully handled UBL namespaces');
});

// Test extraction of invoice items
tap.test('Extract invoice items from XInvoice XML', async () => {
  // Create an invoice with items
  const encoder = new XInvoiceEncoder();
  const xml = encoder.createXInvoiceXml(testLetterData);
  
  // Decode the XML
  const decoder = new XInvoiceDecoder(xml);
  const decodedLetter = await decoder.getLetterData();
  
  // Verify items were extracted
  expect(decodedLetter.content?.invoiceData?.items).toBeDefined();
  if (decodedLetter.content?.invoiceData?.items) {
    // At least one item should be extracted
    expect(decodedLetter.content.invoiceData.items.length).toBeGreaterThan(0);
    
    // Check first item has needed properties
    const firstItem = decodedLetter.content.invoiceData.items[0];
    expect(firstItem.name).toBeDefined();
    expect(firstItem.unitQuantity).toBeDefined();
    expect(firstItem.unitNetPrice).toBeDefined();
  }
  
  console.log('Successfully extracted invoice items');
});

// Start the test suite
tap.start();