import fs from 'node:fs/promises';
import path from 'node:path';
import type { TCachedLicense } from '@documenso/lib/types/license';
import { seedUser } from '@documenso/prisma/seed/users';
import { expect, test } from '@playwright/test';

import { apiSignin } from '../fixtures/authentication';

const LICENSE_FILE_NAME = '.documenso-license.json';
const LICENSE_BACKUP_FILE_NAME = '.documenso-license-backup.json';

/**
 * Get the path to the license file.
 *
 * The server reads from process.cwd() which is apps/remix when the dev server runs.
 * Tests run from packages/app-tests, so we need to go up to the root then into apps/remix.
 */
const getLicenseFilePath = () => {
  // From packages/app-tests/e2e/license -> ../../../../apps/remix/.documenso-license.json
  return path.join(__dirname, '../../../../apps/remix', LICENSE_FILE_NAME);
};

/**
 * Get the path to the backup license file.
 */
const getBackupLicenseFilePath = () => {
  return path.join(__dirname, '../../../../apps/remix', LICENSE_BACKUP_FILE_NAME);
};

/**
 * Backup the existing license file if it exists.
 */
const backupLicenseFile = async () => {
  const licensePath = getLicenseFilePath();
  const backupPath = getBackupLicenseFilePath();

  try {
    await fs.access(licensePath);
    await fs.rename(licensePath, backupPath);
  } catch (e) {
    // File doesn't exist, nothing to backup
    console.log(e);
  }
};

/**
 * Restore the backup license file if it exists.
 */
const restoreLicenseFile = async () => {
  const licensePath = getLicenseFilePath();
  const backupPath = getBackupLicenseFilePath();

  try {
    await fs.access(backupPath);
    await fs.rename(backupPath, licensePath);
  } catch (e) {
    // Backup doesn't exist, nothing to restore
    console.log(e);
  }
};

/**
 * Write a license file with the given data.
 * Pass null to delete the license file.
 */
const writeLicenseFile = async (data: TCachedLicense | null) => {
  const licensePath = getLicenseFilePath();

  if (data === null) {
    await fs.unlink(licensePath).catch(() => {
      // File doesn't exist, ignore
    });
  } else {
    await fs.writeFile(licensePath, JSON.stringify(data, null, 2), 'utf-8');
  }
};

/**
 * Create a mock license object with the given status and unauthorized flag.
 */
const createMockLicense = (
  status: 'ACTIVE' | 'EXPIRED' | 'PAST_DUE',
  unauthorizedFlagUsage: boolean,
): TCachedLicense => {
  return {
    lastChecked: new Date().toISOString(),
    license: {
      status,
      createdAt: new Date(),
      name: 'Test License',
      periodEnd: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), // 30 days from now
      cancelAtPeriodEnd: false,
      licenseKey: 'test-license-key',
      flags: {},
    },
    requestedLicenseKey: 'test-license-key',
    derivedStatus: unauthorizedFlagUsage ? 'UNAUTHORIZED' : status,
    unauthorizedFlagUsage,
  };
};

/**
 * Create a mock license object with no license data (only unauthorized flag).
 */
const createMockUnauthorizedWithoutLicense = (): TCachedLicense => {
  return {
    lastChecked: new Date().toISOString(),
    license: null,
    unauthorizedFlagUsage: true,
    derivedStatus: 'UNAUTHORIZED',
  };
};

// Run tests serially to avoid race conditions with the license file
test.describe.configure({ mode: 'serial' });

// SKIPPING TEST UNTIL WE ADD A WAY TO OVERRIDE THE LICENSE FILE.
test.describe
  .skip('License Status Banner', () => {
    test.beforeAll(async () => {
      // Backup any existing license file before running tests
      await backupLicenseFile();
    });

    test.afterAll(async () => {
      // Restore the backup license file after all tests complete
      await restoreLicenseFile();
    });

    test.beforeEach(async () => {
      // Clean up license file before each test to ensure clean state
      await writeLicenseFile(null);
    });

    test.afterEach(async () => {
      // Clean up license file after each test
      await writeLicenseFile(null);
    });

    test('[ADMIN]: no banner when license file is missing', async ({ page }) => {
      // Ensure no license file exists BEFORE any page loads
      await writeLicenseFile(null);

      const { user: adminUser } = await seedUser({
        isAdmin: true,
      });

      // Navigate to admin page - license is read during page load
      await apiSignin({
        page,
        email: adminUser.email,
        redirectPath: '/admin',
      });

      // Verify we're on the admin page
      await expect(page.getByRole('heading', { name: 'Admin Panel' })).toBeVisible();

      // Global banner should not be visible (no license file)
      await expect(page.getByText('This is an expired license instance of Documenso')).not.toBeVisible();

      // Admin banner messages should not be visible (no license file means no banner)
      await expect(page.getByText('License payment overdue')).not.toBeVisible();
      await expect(page.getByText('License expired')).not.toBeVisible();
      await expect(page.getByText('Invalid License Type')).not.toBeVisible();
      await expect(page.getByText('Missing License')).not.toBeVisible();
    });

    test('[ADMIN]: no banner when license is ACTIVE', async ({ page }) => {
      // Create an ACTIVE license BEFORE any page loads
      await writeLicenseFile(createMockLicense('ACTIVE', false));

      const { user: adminUser } = await seedUser({
        isAdmin: true,
      });

      // Navigate to admin page - license is read during page load
      await apiSignin({
        page,
        email: adminUser.email,
        redirectPath: '/admin',
      });

      // Verify we're on the admin page
      await expect(page.getByRole('heading', { name: 'Admin Panel' })).toBeVisible();

      // Global banner should not be visible (license is ACTIVE)
      await expect(page.getByText('This is an expired license instance of Documenso')).not.toBeVisible();

      // Admin banner messages should not be visible (license is ACTIVE)
      await expect(page.getByText('License payment overdue')).not.toBeVisible();
      await expect(page.getByText('License expired')).not.toBeVisible();
      await expect(page.getByText('Invalid License Type')).not.toBeVisible();
    });

    test('[ADMIN]: admin banner shows PAST_DUE warning', async ({ page }) => {
      // Create a PAST_DUE license BEFORE any page loads
      await writeLicenseFile(createMockLicense('PAST_DUE', false));

      const { user: adminUser } = await seedUser({
        isAdmin: true,
      });

      // Navigate to admin page - license is read during page load
      await apiSignin({
        page,
        email: adminUser.email,
        redirectPath: '/admin',
      });

      // Verify we're on the admin page
      await expect(page.getByRole('heading', { name: 'Admin Panel' })).toBeVisible();

      // Global banner should NOT be visible (only shows for EXPIRED + unauthorized)
      await expect(page.getByText('This is an expired license instance of Documenso')).not.toBeVisible();

      // Admin banner should show PAST_DUE message
      await expect(page.getByText('License payment overdue')).toBeVisible();
      await expect(page.getByText('Please update your payment to avoid service disruptions.')).toBeVisible();

      // Should have the "See Documentation" link
      await expect(page.getByRole('link', { name: 'See Documentation' })).toBeVisible();
    });

    test('[ADMIN]: admin banner shows EXPIRED error', async ({ page }) => {
      // Create an EXPIRED license WITHOUT unauthorized usage BEFORE any page loads
      await writeLicenseFile(createMockLicense('EXPIRED', false));

      const { user: adminUser } = await seedUser({
        isAdmin: true,
      });

      // Navigate to admin page - license is read during page load
      await apiSignin({
        page,
        email: adminUser.email,
        redirectPath: '/admin',
      });

      // Verify we're on the admin page
      await expect(page.getByRole('heading', { name: 'Admin Panel' })).toBeVisible();

      // Global banner should NOT be visible (requires BOTH expired AND unauthorized)
      await expect(page.getByText('This is an expired license instance of Documenso')).not.toBeVisible();

      // Admin banner should show EXPIRED message
      await expect(page.getByText('License expired')).toBeVisible();
      await expect(page.getByText('Please renew your license to continue using enterprise features.')).toBeVisible();

      // Should have the "See Documentation" link
      await expect(page.getByRole('link', { name: 'See Documentation' })).toBeVisible();
    });

    test.skip('[ADMIN]: global banner shows when EXPIRED with unauthorized usage', async ({ page }) => {
      // Create an EXPIRED license WITH unauthorized usage BEFORE any page loads
      await writeLicenseFile(createMockLicense('EXPIRED', true));

      const { user: adminUser } = await seedUser({
        isAdmin: true,
      });

      // Navigate to admin page - license is read during page load
      await apiSignin({
        page,
        email: adminUser.email,
        redirectPath: '/admin',
      });

      // Verify we're on the admin page
      await expect(page.getByRole('heading', { name: 'Admin Panel' })).toBeVisible();

      // Global banner SHOULD be visible (EXPIRED + unauthorized)
      await expect(page.getByText('This is an expired license instance of Documenso')).toBeVisible();

      // Admin banner should show UNAUTHORIZED message (takes precedence over EXPIRED)
      await expect(page.getByText('Invalid License Type')).toBeVisible();
      await expect(
        page.getByText('Your Documenso instance is using features that are not part of your license.'),
      ).toBeVisible();
    });

    test('[ADMIN]: admin banner shows UNAUTHORIZED when flags are misused with license', async ({ page }) => {
      // Create an ACTIVE license but WITH unauthorized flag usage BEFORE any page loads
      await writeLicenseFile(createMockLicense('ACTIVE', true));

      const { user: adminUser } = await seedUser({
        isAdmin: true,
      });

      // Navigate to admin page - license is read during page load
      await apiSignin({
        page,
        email: adminUser.email,
        redirectPath: '/admin',
      });

      // Verify we're on the admin page
      await expect(page.getByRole('heading', { name: 'Admin Panel' })).toBeVisible();

      // Global banner should NOT be visible (requires EXPIRED status)
      await expect(page.getByText('This is an expired license instance of Documenso')).not.toBeVisible();

      // Admin banner should show UNAUTHORIZED message
      await expect(page.getByText('Invalid License Type')).toBeVisible();
      await expect(
        page.getByText('Your Documenso instance is using features that are not part of your license.'),
      ).toBeVisible();

      // Should have the "See Documentation" link
      await expect(page.getByRole('link', { name: 'See Documentation' })).toBeVisible();
    });

    test('[ADMIN]: admin banner shows Invalid License Type when unauthorized without license data', async ({
      page,
    }) => {
      // Create a license file with unauthorized flag but no license data BEFORE any page loads
      // Note: Even without license data, the banner shows "Invalid License Type" because the
      // license file exists (just with license: null). The "Missing License" message would only
      // show if the entire license prop was null, which doesn't happen with a valid file.
      await writeLicenseFile(createMockUnauthorizedWithoutLicense());

      const { user: adminUser } = await seedUser({
        isAdmin: true,
      });

      // Navigate to admin page - license is read during page load
      await apiSignin({
        page,
        email: adminUser.email,
        redirectPath: '/admin',
      });

      // Verify we're on the admin page
      await expect(page.getByRole('heading', { name: 'Admin Panel' })).toBeVisible();

      // Global banner should NOT be visible (no EXPIRED status, only unauthorized flag)
      await expect(page.getByText('This is an expired license instance of Documenso')).not.toBeVisible();

      // Admin banner should show Invalid License Type message (unauthorized flag is set)
      await expect(page.getByText('Invalid License Type')).toBeVisible();
      await expect(
        page.getByText('Your Documenso instance is using features that are not part of your license.'),
      ).toBeVisible();

      // Should have the "See Documentation" link
      await expect(page.getByRole('link', { name: 'See Documentation' })).toBeVisible();
    });

    test.skip('[ADMIN]: global banner visible on non-admin pages when EXPIRED with unauthorized', async ({ page }) => {
      // Create an EXPIRED license WITH unauthorized usage BEFORE any page loads
      await writeLicenseFile(createMockLicense('EXPIRED', true));

      const { user } = await seedUser();

      // Navigate to documents page - license is read during page load
      await apiSignin({
        page,
        email: user.email,
        redirectPath: '/documents',
      });

      // Global banner SHOULD be visible on any authenticated page (EXPIRED + unauthorized)
      await expect(page.getByText('This is an expired license instance of Documenso')).toBeVisible();
    });
  });
