import type { Locator, Page } from "playwright";

/*
  CKEditor - The WYSIWYG Editor https://ckeditor.com/wysiwyg-editor-open-source/
*/
async function CKEditor(
  { page }: { page: Page },
  inputName: string,
  value: string,
): Promise<void> {
  const col = page.locator("td", {
    has: page.locator(`textarea[name="${inputName}"]`),
  });
  // const htmlEditor = col.frameLocator('iframe').locator('body');
  const rawHTMLEditor = col.locator("textarea.cke_editable");

  const htmlToggleBtn = col.getByRole("button").filter({ hasText: /Source/ });
  await htmlToggleBtn.click();
  await rawHTMLEditor.fill(value);
  await htmlToggleBtn.click();
}

/*
  Ace - The High Performance Code Editor for the Web https://ace.c9.io/
*/
async function ACE(
  { page }: { page: Page },
  inputName: string,
  value: string,
): Promise<void> {
  const input = page.locator(`pre[id="${inputName}"]`).locator("textarea");
  await input.focus();
  const CtrlKey = Deno.build.os === 'darwin' ? 'Meta' : 'Control';
  await page.keyboard.press(CtrlKey+"+A")
  await page.keyboard.press("Backspace")
  await input.fill(value);
}

async function toggleOnOff(
  containerLocator: Locator,
  on: boolean,
): Promise<void> {
  const hideBtn = containerLocator.locator(`[title="Désactivé"]`);
  const showBtn = containerLocator.locator(`[title="Actif"], [title="Activé"]`);
  if (!await hideBtn.isVisible() && !await showBtn.isVisible()) {
    throw new Error("Show/Hide button not found");
  }
  if (on && await hideBtn.isVisible()) await hideBtn.click();
  if (!on && await showBtn.isVisible()) await showBtn.click();
}

// Fonction générique `fillForm` pour remplir des formulaires
async function fillForm<T>(
  { page, imgFolderPath }: { page: Page; imgFolderPath: string },
  data: T,
  inputNames: Map<keyof T, string>,
  submit: number = 0, // submit is a number to specify which submit buttton to use, 0 means no submit
) {
  for (const [attr, input] of inputNames) {
    const attrValue = data[attr];
    if (!attrValue) continue;

    const [inputName, inputType] = input.split(":");
    console.log(`${inputName} => '${attrValue}'`);
    switch (inputType) {
      case "select":
        await page.selectOption(`select[name="${inputName}"]`, {
          label: attrValue as string,
        });
        break;
      case "file": {
        const [fileChooser] = await Promise.all([
          page.waitForEvent("filechooser"),
          page.click(`input[name="${inputName}"]`),
        ]);
        await fileChooser.setFiles(
          (attrValue as string).replace("$IMG", imgFolderPath),
        );
        break;
      }
      case "cke":
        CKEditor({ page }, inputName, attrValue as string);
        break;
      case "ace":
        await ACE({ page }, inputName, attrValue as string);
        break;
      case "toggle":
        await toggleOnOff(
          page.locator("tr").filter({
            has: page.locator("td", { hasText: inputName }),
          }),
          Boolean(JSON.parse(attrValue as string)),
        );
        break;
      default:
        await page.fill(
          `input[name="${inputName}"],textarea[name="${inputName}"]`,
          attrValue as string,
        );
    }
  }
  if (submit > 0) {
    await page.click(`:nth-match(input[type="submit"], ${submit})`);
  }
}

export default {
  fillForm,
  toggleOnOff,
  CKEditor,
  ACE,
};
