import fs from 'node:fs/promises';
import path from 'node:path';

import { formatDirectTemplatePath } from '@documenso/lib/utils/templates';
import { prisma } from '@documenso/prisma';
import { seedPendingDocumentWithFullFields } from '@documenso/prisma/seed/documents';
import { seedDirectTemplate } from '@documenso/prisma/seed/templates';
import { seedUser } from '@documenso/prisma/seed/users';
import { expect, type Page, test } from '@playwright/test';
import { DocumentDataType, FieldType } from '@prisma/client';

const BRANDING_URL = 'https://brand.example/signing?source=documenso';
const PDF_PAGE_SELECTOR = 'img[data-page-number]';

const readBrandingLogo = async () => {
  const logo = await fs.readFile(path.join(__dirname, '../../assets/logo.png'));

  return JSON.stringify({
    type: DocumentDataType.BYTES_64,
    data: logo.toString('base64'),
  });
};

const enableOrganisationBranding = async ({
  organisationGlobalSettingsId,
  brandingUrl = BRANDING_URL,
}: {
  organisationGlobalSettingsId: string;
  brandingUrl?: string;
}) => {
  await prisma.organisationGlobalSettings.update({
    where: { id: organisationGlobalSettingsId },
    data: {
      brandingEnabled: true,
      brandingLogo: await readBrandingLogo(),
      brandingUrl,
    },
  });
};

/**
 * On signing surfaces the custom branding logo must render as a plain image.
 * It must not be wrapped in any link, and the Brand Website must never appear
 * as a link on these pages.
 */
const expectPlainBrandingLogo = async (page: Page, logoName: string) => {
  const logo = page.getByRole('img', { name: logoName });

  await expect(logo).toBeVisible();

  // The custom logo must not be wrapped in a link.
  await expect(page.getByRole('link', { name: logoName })).toHaveCount(0);

  // The Brand Website must never be rendered as a link on signing pages.
  await expect(page.locator(`a[href="${BRANDING_URL}"]`)).toHaveCount(0);
};

test('[SIGNING_BRANDING]: V1 normal signing renders custom logo as a plain image', async ({ page }) => {
  const { user, team, organisation } = await seedUser();

  await enableOrganisationBranding({
    organisationGlobalSettingsId: organisation.organisationGlobalSettingsId,
  });

  const { recipients } = await seedPendingDocumentWithFullFields({
    owner: user,
    teamId: team.id,
    recipients: ['v1-branding-signer@test.documenso.com'],
    fields: [FieldType.SIGNATURE],
  });

  await page.goto(`/sign/${recipients[0].token}`);

  await expectPlainBrandingLogo(page, `${team.name}'s Logo`);
});

test('[SIGNING_BRANDING]: V2 signing renders custom logo as a plain image', async ({ page }) => {
  const { user, team, organisation } = await seedUser();

  await enableOrganisationBranding({
    organisationGlobalSettingsId: organisation.organisationGlobalSettingsId,
  });

  const { recipients } = await seedPendingDocumentWithFullFields({
    owner: user,
    teamId: team.id,
    recipients: ['v2-branding-signer@test.documenso.com'],
    fields: [FieldType.SIGNATURE],
    updateDocumentOptions: { internalVersion: 2 },
  });

  const directTemplate = await seedDirectTemplate({
    title: 'V2 Branding Direct Template',
    userId: user.id,
    teamId: team.id,
    internalVersion: 2,
  });

  await page.goto(`/sign/${recipients[0].token}`);
  await expectPlainBrandingLogo(page, `${team.name}'s Logo`);

  await page.goto(formatDirectTemplatePath(directTemplate.directLink?.token || ''));
  await expectPlainBrandingLogo(page, `${team.name}'s Logo`);
});

test('[SIGNING_BRANDING]: V2 signing keeps internal link for the Documenso fallback logo', async ({ page }) => {
  const { user, team } = await seedUser();

  const { recipients } = await seedPendingDocumentWithFullFields({
    owner: user,
    teamId: team.id,
    recipients: ['v2-fallback-signer@test.documenso.com'],
    fields: [FieldType.SIGNATURE],
    updateDocumentOptions: { internalVersion: 2 },
  });

  await page.goto(`/sign/${recipients[0].token}`);

  const fallbackLogoLink = page.locator('a[href="/"]').first();

  await expect(fallbackLogoLink).toBeVisible();
});

test('[SIGNING_BRANDING]: embedded signing does not render custom logo Brand Website links', async ({ page }) => {
  const { user, team, organisation } = await seedUser();

  await enableOrganisationBranding({
    organisationGlobalSettingsId: organisation.organisationGlobalSettingsId,
  });

  const { recipients } = await seedPendingDocumentWithFullFields({
    owner: user,
    teamId: team.id,
    recipients: ['embed-branding-signer@test.documenso.com'],
    fields: [FieldType.SIGNATURE],
    updateDocumentOptions: { internalVersion: 2 },
  });

  await page.goto(`/embed/sign/${recipients[0].token}`);
  await expect(page.locator(PDF_PAGE_SELECTOR).first()).toBeVisible({ timeout: 30_000 });

  await expect(page.locator(`a[href="${BRANDING_URL}"]`)).toHaveCount(0);
  await expect(page.getByRole('link', { name: `${team.name}'s Logo` })).toHaveCount(0);
});

test('[SIGNING_BRANDING]: custom logo renders when branding is enabled and is hidden when disabled', async ({
  page,
}) => {
  const { user, team, organisation } = await seedUser();

  await enableOrganisationBranding({
    organisationGlobalSettingsId: organisation.organisationGlobalSettingsId,
  });

  const { recipients } = await seedPendingDocumentWithFullFields({
    owner: user,
    teamId: team.id,
    recipients: ['enabled-disabled-branding-signer@test.documenso.com'],
    fields: [FieldType.SIGNATURE],
    updateDocumentOptions: { internalVersion: 2 },
  });

  // Branding enabled → the custom logo is rendered on the signing page.
  await page.goto(`/sign/${recipients[0].token}`);
  await expectPlainBrandingLogo(page, `${team.name}'s Logo`);

  // Disable branding while keeping the stored logo (the team inherits this).
  await prisma.organisationGlobalSettings.update({
    where: { id: organisation.organisationGlobalSettingsId },
    data: { brandingEnabled: false },
  });

  // Branding disabled → the custom logo is gone and the Documenso fallback
  // (an internal link to "/") is shown instead.
  await page.goto(`/sign/${recipients[0].token}`);

  await expect(page.getByRole('img', { name: `${team.name}'s Logo` })).toHaveCount(0);
  await expect(page.locator('a[href="/"]').first()).toBeVisible();
});
