import { test, expect } from '@playwright/test';
import { adminPath } from './helpers.mjs';
import { ensureDataSource, ensureMailshot, cleanupByNames } from './helpers.mjs';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const invoicingHtml = fs.readFileSync(path.resolve(__dirname, '../../../samples/invoicing.html'), 'utf8');

const setJoditHtml = async (page, html) => {
  await page.evaluate((nextHtml) => {
    const host = /** @type {any} */ (document.getElementById('ms-template-jodit'));
    const instances = (window.Jodit && window.Jodit.instances) ? window.Jodit.instances : null;
    let jodit = host && host.jodit ? host.jodit : null;
    if (!jodit && instances) {
      jodit = instances['ms-template-jodit'] || instances.ms_template_jodit || null;
    }
    if (!jodit && instances && typeof instances === 'object') {
      const vals = Array.isArray(instances) ? instances : Object.values(instances);
      jodit = vals.find((x) => x && x.container && x.container.isConnected) || null;
    }
    if (!jodit) {
      throw new Error('Jodit instance not available');
    }
    if (typeof jodit.setEditorValue === 'function') {
      jodit.setEditorValue(nextHtml);
    } else {
      jodit.value = nextHtml;
    }
    if (typeof jodit.synchronizeValues === 'function') {
      jodit.synchronizeValues();
    }
  }, html);
};

const ensureMailshotModalsClosed = async (page) => {
  const acceptDialog = async (dialog) => {
    await dialog.accept();
  };
  page.on('dialog', acceptDialog);
  try {
    const templateModal = page.locator('#ms-template-modal');
    if (await templateModal.isVisible().catch(() => false)) {
      await page.locator('#ms-template-close').click();
      await expect(templateModal).toBeHidden();
    }

    const editorModal = page.locator('#ms-editor-modal');
    if (await editorModal.isVisible().catch(() => false)) {
      await page.locator('#ms-close-editor').click();
      await expect(editorModal).toBeHidden();
    }
  } finally {
    page.off('dialog', acceptDialog);
  }
};

const openNewMailshotEditor = async (page) => {
  await ensureMailshotModalsClosed(page);
  await page.locator('#ms-open-new').click();
  await expect(page.locator('#ms-editor-modal')).toBeVisible();
};

test('regression: mailshot message modal saves and closes on first click', async ({ page }) => {
  const longBody = Array.from({ length: 120 }, (_, i) => `<p>Line ${i + 1}</p>`).join('');
  const html = `<style>body{font-family:Cambria, serif;}</style><div class="regression-one-click">One click save marker</div>${longBody}<div id="tail-marker">Tail marker</div>`;

  await page.goto(adminPath('feca-mailshots-mailshots'));
  await expect(page.locator('h1', { hasText: 'Mailshots' })).toBeVisible();

  await openNewMailshotEditor(page);

  await page.locator('#ms-edit-message').click();
  await expect(page.locator('#ms-template-modal')).toBeVisible();
  await setJoditHtml(page, html);

  await page.locator('#ms-template-save').click();
  await expect(page.locator('#ms-template-modal')).toBeHidden();
  await expect(page.locator('#ms_message')).toHaveValue(/regression-one-click/);
  await expect(page.locator('#ms_message')).toHaveValue(/tail-marker/);
  await expect(page.locator('#ms-message-snippet')).toContainText('One click save marker');
});

test('regression: message editor single-save with invoicing template (scroll case)', async ({ page }) => {
  await page.goto(adminPath('feca-mailshots-mailshots'));
  await expect(page.locator('h1', { hasText: 'Mailshots' })).toBeVisible();

  await openNewMailshotEditor(page);

  await page.locator('#ms-edit-message').click();
  await expect(page.locator('#ms-template-modal')).toBeVisible();
  await setJoditHtml(page, invoicingHtml);

  await page.evaluate(() => {
    const host = /** @type {HTMLTextAreaElement|null} */ (document.getElementById('ms-template-jodit'));
    if (host) {
      host.scrollTop = host.scrollHeight;
      host.focus();
    }
    const modal = document.getElementById('ms-template-modal');
    if (!modal) { return; }
    const areas = modal.querySelectorAll('textarea');
    areas.forEach((ta) => {
      const el = /** @type {HTMLTextAreaElement} */ (ta);
      el.scrollTop = el.scrollHeight;
      el.focus();
    });
  });

  await page.locator('#ms-template-save').click();
  await expect(page.locator('#ms-template-modal')).toBeHidden();
  await expect(page.locator('#ms_message')).toHaveValue(/invoice-header/);
  await expect(page.locator('#ms_message')).toHaveValue(/Registered Charity No\. 293020/);
});

test('regression: message editor manual source edit saves on first click', async ({ page }) => {
  await page.goto(adminPath('feca-mailshots-mailshots'));
  await expect(page.locator('h1', { hasText: 'Mailshots' })).toBeVisible();

  await openNewMailshotEditor(page);

  await page.locator('#ms-edit-message').click();
  await expect(page.locator('#ms-template-modal')).toBeVisible();
  await setJoditHtml(page, invoicingHtml);

  await page.evaluate(() => {
    const modal = document.getElementById('ms-template-modal');
    if (!modal) { return; }
    const sourceAreas = Array.from(modal.querySelectorAll('textarea'))
      .filter((el) => el.offsetParent !== null);
    const source = sourceAreas[sourceAreas.length - 1] || null;
    if (!source) { return; }
    source.scrollTop = source.scrollHeight;
    source.focus();
    source.setSelectionRange(source.value.length, source.value.length);
    source.value = `${source.value}\n<!-- manual-edit-marker -->`;
    source.dispatchEvent(new Event('input', { bubbles: true }));
    source.dispatchEvent(new Event('change', { bubbles: true }));
  });

  await page.locator('#ms-template-save').click();
  await expect(page.locator('#ms-template-modal')).toBeHidden();
  await expect(page.locator('#ms_message')).toHaveValue(/manual-edit-marker/);
  await expect(page.locator('#ms_message')).toHaveValue(/invoice-header/);
});

test('regression: mailshot validation failure keeps entered values in modal', async ({ page }) => {
  await page.goto(adminPath('feca-mailshots-mailshots'));
  await expect(page.locator('h1', { hasText: 'Mailshots' })).toBeVisible();

  await openNewMailshotEditor(page);

  await page.locator('#ms_purpose').fill('validation draft mailshot');
  await page.locator('#ms_subject').fill('');
  await page.locator('#ms-edit-message').click();
  await expect(page.locator('#ms-template-modal')).toBeVisible();
  await setJoditHtml(page, '<p>Draft body should survive validation failure</p>');
  await page.locator('#ms-template-save').click();
  await expect(page.locator('#ms-template-modal')).toBeHidden();

  await page.locator('#mailshot-editor button[type="submit"]').click();
  await expect(page.locator('#ms-editor-modal')).toBeVisible();
  await expect(page.locator('#mailshot-editor')).toContainText('Please fix the following:');
  await expect(page.locator('#mailshot-editor')).toContainText('Subject is required.');
  await expect(page.locator('.wrap')).not.toContainText('Mailshot action failed.');
  await expect(page.locator('#ms_purpose')).toHaveValue('validation draft mailshot');
  await expect(page.locator('#ms_message')).toHaveValue(/Draft body should survive validation failure/);
});

test('regression: editing existing mailshot allows empty message for pdf-only workflow', async ({ page, request }) => {
  const uniq = `${Date.now()}_${Math.floor(Math.random() * 100000)}`;
  const dsName = `e2e_ms_edit_ds_${uniq}`;
  const purpose = `e2e_mailshot_edit_${uniq}`;
  const editedPurpose = `${purpose}_edited`;
  let mailshotId = '';

  try {
    await ensureDataSource(request, dsName, 'contacts');
    const saved = await ensureMailshot(request, {
      Purpose: purpose,
      DataSource: dsName,
      CC: '',
      BCC: '',
      Subject: 'Original subject',
      Message: '<p>Original message</p>',
      PDFAttachment: '',
      AttachmentNames: '[]',
      PDFFilenameDerivedFrom: '',
      RecipientEmailField: 'contacts.contact_email_1',
      ReplyTo: ''
    });
    mailshotId = String(saved.id || '');

    await page.goto(`${adminPath('feca-mailshots-mailshots')}&edit_id=${encodeURIComponent(mailshotId)}`);
    await expect(page.locator('#ms-editor-modal')).toBeVisible();

    await page.locator('#ms_purpose').fill(editedPurpose);
    await page.locator('#ms_subject').fill('Edited subject');
    await page.locator('#ms-edit-message').click();
    await expect(page.locator('#ms-template-modal')).toBeVisible();
    await setJoditHtml(page, '');
    await page.locator('#ms-template-save').click();
    await expect(page.locator('#ms-template-modal')).toBeHidden();
    await page.locator('#mailshot-editor button[type="submit"]').click();

    await expect(page.locator('#ms-editor-modal')).toBeHidden();
    await expect(page.getByRole('cell', { name: editedPurpose })).toBeVisible();
  } finally {
    try {
      await cleanupByNames(request, { dataSourceNames: [dsName], mailshotPurposes: [purpose, editedPurpose] });
    } catch {
      // best effort
    }
  }
});

test('regression: attachments new button opens modal editor', async ({ page }) => {
  await page.goto(adminPath('feca-mailshots-attachments'));
  await expect(page.locator('h1', { hasText: 'Attachments' })).toBeVisible();

  await page.locator('#att-open-new').click();
  await expect(page.locator('#att-editor-modal')).toBeVisible();
  await expect(page.locator('#att-editor-form')).toBeVisible();
  await expect(page.locator('#att-editor-id')).toHaveValue('');
});

test('regression: attachments upload populates filename and failed save preserves data', async ({ page }) => {
  await page.goto(adminPath('feca-mailshots-attachments'));
  await expect(page.locator('h1', { hasText: 'Attachments' })).toBeVisible();

  await page.locator('#att-open-new').click();
  await expect(page.locator('#att-editor-modal')).toBeVisible();
  await page.locator('#att_name').fill('draft_attachment');
  await page.setInputFiles('#att_file_upload', {
    name: 'sample-attachment.txt',
    mimeType: 'text/plain',
    buffer: Buffer.from('attachment regression sample', 'utf8')
  });
  await expect(page.locator('#att_file_name')).toHaveValue('sample-attachment.txt');
  await page.locator('#att_name').fill('');

  await page.getByRole('button', { name: 'Create Attachment' }).click();
  await expect(page.locator('#att-editor-modal')).toBeVisible();
  await expect(page.locator('#att-editor-form')).toContainText('Please fix the following:');
  await expect(page.locator('#att-editor-form')).toContainText('name is required.');
  await expect(page.locator('#att_file_name')).toHaveValue('sample-attachment.txt');
  await expect(page.locator('#att_base64')).not.toHaveValue('');
});

test('regression: pdf assets new button opens modal editor', async ({ page }) => {
  await page.goto(adminPath('feca-mailshots-pdf-assets'));
  await expect(page.locator('h1', { hasText: 'PDF Assets' })).toBeVisible();

  await page.locator('#pdf-open-new').click();
  await expect(page.locator('#pdf-editor-modal')).toBeVisible();
  await expect(page.locator('#pdf-editor-form')).toBeVisible();
  await expect(page.locator('#pdf-editor-id')).toHaveValue('');
});

test('regression: pdf assets failed save keeps modal values and shows inline errors', async ({ page }) => {
  await page.goto(adminPath('feca-mailshots-pdf-assets'));
  await expect(page.locator('h1', { hasText: 'PDF Assets' })).toBeVisible();

  await page.locator('#pdf-open-new').click();
  await expect(page.locator('#pdf-editor-modal')).toBeVisible();

  await page.locator('#pdf_name').fill('draft_pdf_asset');
  await page.locator('#pdf_width').fill('');
  await page.locator('#pdf_height').fill('');
  await page.locator('#pdf_file_name').fill('');
  await page.setInputFiles('#pdf_file_upload', {
    name: 'sample-asset.png',
    mimeType: 'image/png',
    buffer: Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00])
  });
  await expect(page.locator('#pdf_file_name')).toHaveValue('sample-asset.png');
  await page.locator('#pdf_file_name').fill('');

  await page.getByRole('button', { name: 'Create PDF Asset' }).click();
  await expect(page.locator('#pdf-editor-modal')).toBeVisible();
  await expect(page.locator('#pdf-editor-form')).toContainText('Please fix the following:');
  await expect(page.locator('#pdf-editor-form')).toContainText('file_name is required.');
  await expect(page.locator('#pdf-editor-form')).toContainText('width_mm and height_mm must be > 0.');
  await expect(page.locator('#pdf_name')).toHaveValue('draft_pdf_asset');
  await expect(page.locator('#pdf_base64')).not.toHaveValue('');
});
