import { generateDatabaseId } from '@documenso/lib/universal/id';
import { prisma } from '@documenso/prisma';
import {
  seedCompletedDocument,
  seedDocuments,
  seedDraftDocument,
  seedPendingDocument,
} from '@documenso/prisma/seed/documents';
import { seedOrganisationMembers } from '@documenso/prisma/seed/organisations';
import { seedTeam, seedTeamEmail, seedTeamMember } from '@documenso/prisma/seed/teams';
import { seedUser } from '@documenso/prisma/seed/users';
import { expect, test } from '@playwright/test';
import {
  DocumentStatus,
  DocumentVisibility,
  OrganisationMemberRole,
  RecipientRole,
  SigningStatus,
  TeamMemberRole,
} from '@prisma/client';

import { apiSignin, apiSignout } from '../fixtures/authentication';
import { checkDocumentCounts, checkDocumentTabCount, toggleDocumentSenderFilter } from '../fixtures/documents';

test.describe.configure({
  mode: 'parallel',
});

test.describe('Find Documents UI - Personal Context', () => {
  test('should show all owned documents across statuses', async ({ page }) => {
    const { user: owner, team, organisation } = await seedUser();
    const { user: recipient } = await seedUser();

    await seedDocuments([
      {
        sender: owner,
        teamId: team.id,
        recipients: [],
        type: DocumentStatus.DRAFT,
        documentOptions: { title: 'Personal Draft Doc' },
      },
      {
        sender: owner,
        teamId: team.id,
        recipients: [recipient],
        type: DocumentStatus.PENDING,
        documentOptions: { title: 'Personal Pending Doc' },
      },
      {
        sender: owner,
        teamId: team.id,
        recipients: [recipient],
        type: DocumentStatus.COMPLETED,
        documentOptions: { title: 'Personal Completed Doc' },
      },
    ]);

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${team.url}/documents`,
    });

    await checkDocumentCounts(page, { draft: 1, pending: 1, completed: 1, all: 3 });
  });

  test('received documents from other teams should NOT appear in personal context', async ({ page }) => {
    // The UI always uses the team code path (findTeamDocumentsFilter) which filters by teamId.
    // Documents sent TO a user by another user's team live on the sender's teamId,
    // so they do NOT appear in the recipient's personal team context.
    const { user: owner, team: ownerTeam } = await seedUser();
    const { user: sender, team: senderTeam } = await seedUser();

    // Owner has their own doc (positive control — should appear)
    await seedDraftDocument(owner, ownerTeam.id, [], {
      createDocumentOptions: { title: 'Owner Own Draft' },
    });

    // Sender sends docs to owner (these live on senderTeam, NOT ownerTeam)
    await seedPendingDocument(sender, senderTeam.id, [owner], {
      createDocumentOptions: { title: 'Received Pending Doc' },
    });
    await seedCompletedDocument(sender, senderTeam.id, [owner], {
      createDocumentOptions: { title: 'Received Completed Doc' },
    });

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${ownerTeam.url}/documents`,
    });

    // Only the owner's own doc should appear (received docs are on sender's team)
    await checkDocumentTabCount(page, 'All', 1);
    await expect(page.getByRole('link', { name: 'Owner Own Draft' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Received Pending Doc', exact: true })).not.toBeVisible();
    await expect(page.getByRole('link', { name: 'Received Completed Doc', exact: true })).not.toBeVisible();
  });

  test('should NOT show documents from other users', async ({ page }) => {
    const { user: userA, team: teamA } = await seedUser();
    const { user: userB, team: teamB } = await seedUser();

    await seedDraftDocument(userB, teamB.id, [], {
      createDocumentOptions: { title: 'UserB Secret Document' },
    });

    await apiSignin({
      page,
      email: userA.email,
      redirectPath: `/t/${teamA.url}/documents`,
    });

    await checkDocumentTabCount(page, 'All', 0);
    await expect(page.getByRole('link', { name: 'UserB Secret Document', exact: true })).not.toBeVisible();
  });

  test('personal context without team email should show 0 inbox', async ({ page }) => {
    // The UI uses the team code path. Without a teamEmail, INBOX returns null (empty).
    // Received docs from other teams don't appear in the user's personal team context.
    const { user: owner, team: ownerTeam } = await seedUser();
    const { user: sender, team: senderTeam } = await seedUser();

    // Sender sends a pending doc to owner (lives on sender's team, not owner's)
    await seedPendingDocument(sender, senderTeam.id, [owner], {
      createDocumentOptions: { title: 'Inbox Document for Owner' },
    });

    // Owner has their own doc (positive control)
    await seedDraftDocument(owner, ownerTeam.id, [], {
      createDocumentOptions: { title: 'Owner Draft Control' },
    });

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${ownerTeam.url}/documents`,
    });

    // Inbox should be 0 since there's no team email and received docs are on sender's team.
    // Owner's own doc should still show in All.
    await checkDocumentCounts(page, { inbox: 0, all: 1 });
    await expect(page.getByRole('link', { name: 'Owner Draft Control' })).toBeVisible();
  });

  test('should filter documents by search query', async ({ page }) => {
    const { user: owner, team } = await seedUser();

    await seedDraftDocument(owner, team.id, [], {
      createDocumentOptions: { title: 'Quarterly Report 2024' },
    });
    await seedDraftDocument(owner, team.id, [], {
      createDocumentOptions: { title: 'Annual Budget Plan' },
    });

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${team.url}/documents`,
    });

    await page.getByPlaceholder('Search documents...').fill('Quarterly');
    await page.waitForURL(/query=Quarterly/);

    await checkDocumentTabCount(page, 'All', 1);
    await expect(page.getByRole('link', { name: 'Quarterly Report 2024' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Annual Budget Plan', exact: true })).not.toBeVisible();
  });

  test('should not show deleted documents', async ({ page }) => {
    const { user: owner, team } = await seedUser();

    const doc = await seedDraftDocument(owner, team.id, [], {
      createDocumentOptions: { title: 'Deleted Personal Doc' },
    });
    await prisma.envelope.update({
      where: { id: doc.id },
      data: { deletedAt: new Date() },
    });

    await seedDraftDocument(owner, team.id, [], {
      createDocumentOptions: { title: 'Active Personal Doc' },
    });

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${team.url}/documents`,
    });

    await checkDocumentTabCount(page, 'All', 1);
    await expect(page.getByRole('link', { name: 'Active Personal Doc' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Deleted Personal Doc', exact: true })).not.toBeVisible();
  });

  test('should only show root-level documents when not in a folder', async ({ page }) => {
    const { user: owner, team } = await seedUser();

    const folder = await prisma.folder.create({
      data: {
        name: 'My Folder',
        teamId: team.id,
        userId: owner.id,
        type: 'DOCUMENT',
      },
    });

    await seedDraftDocument(owner, team.id, [], {
      createDocumentOptions: { title: 'Root Level Doc', folderId: null },
    });
    await seedDraftDocument(owner, team.id, [], {
      createDocumentOptions: { title: 'Folder Level Doc', folderId: folder.id },
    });

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${team.url}/documents`,
    });

    await checkDocumentTabCount(page, 'All', 1);
    await expect(page.getByRole('link', { name: 'Root Level Doc' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Folder Level Doc', exact: true })).not.toBeVisible();
  });
});

test.describe('Find Documents UI - Team Context', () => {
  test('should show team documents to all team members', async ({ page }) => {
    const { team, owner } = await seedTeam();

    const member = await seedTeamMember({ teamId: team.id, role: TeamMemberRole.MEMBER });
    const { user: outsideUser, team: outsideTeam } = await seedUser();

    // Seed multiple team docs across statuses
    await seedDocuments([
      {
        sender: owner,
        teamId: team.id,
        recipients: [outsideUser],
        type: DocumentStatus.PENDING,
        documentOptions: { title: 'Team Pending Doc' },
      },
      {
        sender: owner,
        teamId: team.id,
        recipients: [],
        type: DocumentStatus.DRAFT,
        documentOptions: { title: 'Team Draft Doc' },
      },
      {
        sender: owner,
        teamId: team.id,
        recipients: [outsideUser],
        type: DocumentStatus.COMPLETED,
        documentOptions: { title: 'Team Completed Doc' },
      },
    ]);

    // Noise: outside user's docs should NOT appear
    await seedDraftDocument(outsideUser, outsideTeam.id, [], {
      createDocumentOptions: { title: 'Outside Noise Doc' },
    });

    // Both owner and member should see the 3 team documents
    for (const user of [owner, member]) {
      await apiSignin({
        page,
        email: user.email,
        redirectPath: `/t/${team.url}/documents`,
      });

      await checkDocumentTabCount(page, 'All', 3);
      await expect(page.getByRole('link', { name: 'Team Pending Doc' })).toBeVisible();
      await expect(page.getByRole('link', { name: 'Team Draft Doc' })).toBeVisible();
      await expect(page.getByRole('link', { name: 'Team Completed Doc' })).toBeVisible();
      await expect(page.getByRole('link', { name: 'Outside Noise Doc', exact: true })).not.toBeVisible();

      await apiSignout({ page });
    }
  });

  test('should NOT show documents from other teams', async ({ page }) => {
    const { team: teamA, owner: ownerA } = await seedTeam();
    const { team: teamB, owner: ownerB } = await seedTeam();

    const memberA = await seedTeamMember({ teamId: teamA.id, role: TeamMemberRole.MEMBER });

    // Multiple docs per team to ensure isolation is thorough
    await seedDocuments([
      {
        sender: ownerA,
        teamId: teamA.id,
        recipients: [],
        type: DocumentStatus.DRAFT,
        documentOptions: { title: 'Team A Draft' },
      },
      {
        sender: ownerA,
        teamId: teamA.id,
        recipients: [],
        type: DocumentStatus.COMPLETED,
        documentOptions: { title: 'Team A Completed' },
      },
      {
        sender: ownerB,
        teamId: teamB.id,
        recipients: [],
        type: DocumentStatus.DRAFT,
        documentOptions: { title: 'Team B Draft' },
      },
      {
        sender: ownerB,
        teamId: teamB.id,
        recipients: [],
        type: DocumentStatus.COMPLETED,
        documentOptions: { title: 'Team B Completed' },
      },
    ]);

    await apiSignin({
      page,
      email: memberA.email,
      redirectPath: `/t/${teamA.url}/documents`,
    });

    await checkDocumentTabCount(page, 'All', 2);
    await expect(page.getByRole('link', { name: 'Team A Draft' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Team A Completed' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Team B Draft', exact: true })).not.toBeVisible();
    await expect(page.getByRole('link', { name: 'Team B Completed', exact: true })).not.toBeVisible();
  });

  test('should NOT show personal documents in team context', async ({ page }) => {
    const { team, owner } = await seedTeam();

    const member = await seedTeamMember({ teamId: team.id, role: TeamMemberRole.MEMBER });

    // Get member's personal team (seedUser creates an org with ownerUserId set)
    const memberOrg = await prisma.organisation.findFirstOrThrow({
      where: {
        ownerUserId: member.id,
      },
      include: {
        teams: true,
      },
    });

    const personalTeamId = memberOrg.teams[0].id;

    await seedDraftDocument(member, personalTeamId, [], {
      createDocumentOptions: { title: 'Personal Doc not in Team' },
    });

    await seedDraftDocument(member, team.id, [], {
      createDocumentOptions: { title: 'Team Doc by Member' },
    });

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${team.url}/documents`,
    });

    await expect(page.getByRole('link', { name: 'Team Doc by Member' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Personal Doc not in Team', exact: true })).not.toBeVisible();
  });

  test('should enforce ADMIN visibility correctly across roles', async ({ page }) => {
    const { user: owner, organisation, team } = await seedUser();

    const [adminUser, managerUser, memberUser] = await seedOrganisationMembers({
      organisationId: organisation.id,
      members: [
        { organisationRole: OrganisationMemberRole.ADMIN },
        { organisationRole: OrganisationMemberRole.MEMBER },
        { organisationRole: OrganisationMemberRole.MEMBER },
      ],
    });

    // Make managerUser actually a MANAGER in the team
    const managerTeamGroup = await prisma.teamGroup.findFirstOrThrow({
      where: { teamId: team.id, teamRole: TeamMemberRole.MANAGER },
      include: { organisationGroup: true },
    });
    const managerOrgMember = await prisma.organisationMember.findFirstOrThrow({
      where: { organisationId: organisation.id, userId: managerUser.id },
    });
    await prisma.organisationGroupMember.create({
      data: {
        id: generateDatabaseId('group_member'),
        groupId: managerTeamGroup.organisationGroupId,
        organisationMemberId: managerOrgMember.id,
      },
    });

    await seedDocuments([
      {
        sender: owner,
        teamId: team.id,
        recipients: [],
        type: DocumentStatus.COMPLETED,
        documentOptions: {
          title: 'Admin Only Doc',
          visibility: DocumentVisibility.ADMIN,
        },
      },
      {
        sender: owner,
        teamId: team.id,
        recipients: [],
        type: DocumentStatus.COMPLETED,
        documentOptions: {
          title: 'Manager Plus Doc',
          visibility: DocumentVisibility.MANAGER_AND_ABOVE,
        },
      },
      {
        sender: owner,
        teamId: team.id,
        recipients: [],
        type: DocumentStatus.COMPLETED,
        documentOptions: {
          title: 'Everyone Doc',
          visibility: DocumentVisibility.EVERYONE,
        },
      },
    ]);

    // Admin sees all 3
    await apiSignin({
      page,
      email: adminUser.email,
      redirectPath: `/t/${team.url}/documents?status=COMPLETED`,
    });
    await checkDocumentTabCount(page, 'Completed', 3);
    await apiSignout({ page });

    // Manager sees 2 (Everyone + Manager+)
    await apiSignin({
      page,
      email: managerUser.email,
      redirectPath: `/t/${team.url}/documents?status=COMPLETED`,
    });
    await checkDocumentTabCount(page, 'Completed', 2);
    await expect(page.getByRole('link', { name: 'Everyone Doc' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Manager Plus Doc' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Admin Only Doc', exact: true })).not.toBeVisible();
    await apiSignout({ page });

    // Member sees 1 (Everyone only)
    await apiSignin({
      page,
      email: memberUser.email,
      redirectPath: `/t/${team.url}/documents?status=COMPLETED`,
    });
    await checkDocumentTabCount(page, 'Completed', 1);
    await expect(page.getByRole('link', { name: 'Everyone Doc' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Manager Plus Doc', exact: true })).not.toBeVisible();
    await expect(page.getByRole('link', { name: 'Admin Only Doc', exact: true })).not.toBeVisible();
    await apiSignout({ page });
  });

  test('document owner sees their document regardless of visibility restriction', async ({ page }) => {
    const { team, owner } = await seedTeam();

    const member = await seedTeamMember({ teamId: team.id, role: TeamMemberRole.MEMBER });

    // Member creates an ADMIN-visibility document (should see as owner)
    // Owner also creates an ADMIN doc (member should NOT see this one)
    // Owner creates an EVERYONE doc (positive control, member should see)
    await seedDocuments([
      {
        sender: member,
        teamId: team.id,
        recipients: [],
        type: DocumentStatus.COMPLETED,
        documentOptions: {
          title: 'Member Owned Admin Doc',
          visibility: DocumentVisibility.ADMIN,
        },
      },
      {
        sender: owner,
        teamId: team.id,
        recipients: [],
        type: DocumentStatus.COMPLETED,
        documentOptions: {
          title: 'Owner Admin Doc Hidden',
          visibility: DocumentVisibility.ADMIN,
        },
      },
      {
        sender: owner,
        teamId: team.id,
        recipients: [],
        type: DocumentStatus.COMPLETED,
        documentOptions: {
          title: 'Everyone Doc Control',
          visibility: DocumentVisibility.EVERYONE,
        },
      },
    ]);

    await apiSignin({
      page,
      email: member.email,
      redirectPath: `/t/${team.url}/documents?status=COMPLETED`,
    });

    // Member sees: their own ADMIN doc + EVERYONE doc, but NOT owner's ADMIN doc
    await checkDocumentTabCount(page, 'Completed', 2);
    await expect(page.getByRole('link', { name: 'Member Owned Admin Doc' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Everyone Doc Control' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Owner Admin Doc Hidden', exact: true })).not.toBeVisible();

    await apiSignout({ page });
  });

  test('recipient sees document regardless of visibility restriction', async ({ page }) => {
    const { team, owner } = await seedTeam();

    const member = await seedTeamMember({ teamId: team.id, role: TeamMemberRole.MEMBER });

    // Owner creates ADMIN-only doc WITH member as recipient (member should see)
    // Owner creates ADMIN-only doc WITHOUT member as recipient (member should NOT see)
    // Owner creates EVERYONE doc (positive control)
    await seedDocuments([
      {
        sender: owner,
        teamId: team.id,
        recipients: [member],
        type: DocumentStatus.COMPLETED,
        documentOptions: {
          title: 'Admin Doc Member Recipient',
          visibility: DocumentVisibility.ADMIN,
        },
      },
      {
        sender: owner,
        teamId: team.id,
        recipients: [],
        type: DocumentStatus.COMPLETED,
        documentOptions: {
          title: 'Admin Doc No Member',
          visibility: DocumentVisibility.ADMIN,
        },
      },
      {
        sender: owner,
        teamId: team.id,
        recipients: [],
        type: DocumentStatus.COMPLETED,
        documentOptions: {
          title: 'Everyone Doc Baseline',
          visibility: DocumentVisibility.EVERYONE,
        },
      },
    ]);

    await apiSignin({
      page,
      email: member.email,
      redirectPath: `/t/${team.url}/documents?status=COMPLETED`,
    });

    // Member sees: ADMIN doc as recipient + EVERYONE doc, but NOT the ADMIN doc without them
    await checkDocumentTabCount(page, 'Completed', 2);
    await expect(page.getByRole('link', { name: 'Admin Doc Member Recipient' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Everyone Doc Baseline' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Admin Doc No Member', exact: true })).not.toBeVisible();

    await apiSignout({ page });
  });
});

test.describe('Find Documents UI - Team with Team Email', () => {
  test('should show documents sent TO team email', async ({ page }) => {
    const { team, owner } = await seedTeam();

    const teamEmail = `team-ui-email-${team.id}@test.documenso.com`;
    await seedTeamEmail({ email: teamEmail, teamId: team.id });

    const { user: externalUser, team: externalTeam } = await seedUser();
    const { user: externalUser2, team: externalTeam2 } = await seedUser();

    await seedDocuments([
      {
        sender: externalUser,
        teamId: externalTeam.id,
        recipients: [teamEmail],
        type: DocumentStatus.PENDING,
        documentOptions: { title: 'Email Received Pending' },
      },
      {
        sender: externalUser,
        teamId: externalTeam.id,
        recipients: [teamEmail],
        type: DocumentStatus.COMPLETED,
        documentOptions: { title: 'Email Received Completed' },
      },
    ]);

    // Noise: docs between external users (should NOT appear in team context)
    await seedPendingDocument(externalUser, externalTeam.id, [externalUser2], {
      createDocumentOptions: { title: 'External Noise Pending' },
    });

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${team.url}/documents`,
    });

    // Should show received pending and completed docs but not noise
    // Note: Received-via-email docs render as <span> not <a> since they belong to external teams
    await checkDocumentTabCount(page, 'All', 2);
    await expect(page.getByRole('cell', { name: 'Email Received Pending' })).toBeVisible();
    await expect(page.getByRole('cell', { name: 'External Noise Pending' })).not.toBeVisible();

    await checkDocumentTabCount(page, 'Completed', 1);
    await expect(page.getByRole('cell', { name: 'Email Received Completed' })).toBeVisible();
  });

  test('should NOT show drafts sent TO team email', async ({ page }) => {
    const { team, owner } = await seedTeam();

    const teamEmail = `team-ui-draft-${team.id}@test.documenso.com`;
    await seedTeamEmail({ email: teamEmail, teamId: team.id });

    const { user: externalUser, team: externalTeam } = await seedUser();

    // Draft to team email (should NOT appear)
    await seedDraftDocument(externalUser, externalTeam.id, [teamEmail], {
      createDocumentOptions: { title: 'Draft To Team Email' },
    });

    // Pending to team email (positive control - SHOULD appear)
    await seedPendingDocument(externalUser, externalTeam.id, [teamEmail], {
      createDocumentOptions: { title: 'Pending To Team Email' },
    });

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${team.url}/documents`,
    });

    // Should see the pending doc but NOT the draft
    // Received-via-email docs render as <span> not <a>
    await checkDocumentTabCount(page, 'All', 1);
    await expect(page.getByRole('cell', { name: 'Pending To Team Email' })).toBeVisible();
    await expect(page.getByRole('cell', { name: 'Draft To Team Email' })).not.toBeVisible();
  });

  test('should show inbox count for team email recipients', async ({ page }) => {
    const { team, owner } = await seedTeam();

    const teamEmail = `team-ui-inbox-${team.id}@test.documenso.com`;
    await seedTeamEmail({ email: teamEmail, teamId: team.id });

    const { user: sender1, team: sender1Team } = await seedUser();
    const { user: sender2, team: sender2Team } = await seedUser();

    await seedDocuments([
      {
        sender: sender1,
        teamId: sender1Team.id,
        recipients: [teamEmail],
        type: DocumentStatus.PENDING,
        documentOptions: { title: 'Inbox Doc 1' },
      },
      {
        sender: sender2,
        teamId: sender2Team.id,
        recipients: [teamEmail],
        type: DocumentStatus.PENDING,
        documentOptions: { title: 'Inbox Doc 2' },
      },
    ]);

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${team.url}/documents`,
    });

    await checkDocumentTabCount(page, 'Inbox', 2);
  });

  test('team without team email should show 0 inbox', async ({ page }) => {
    const { team, owner } = await seedTeam();

    // No team email set up
    const { user: outsideUser, team: outsideTeam } = await seedUser();

    await seedPendingDocument(owner, team.id, [outsideUser], {
      createDocumentOptions: { title: 'Pending Without Inbox' },
    });

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${team.url}/documents`,
    });

    // Inbox should be 0, but pending should still show.
    await checkDocumentCounts(page, { inbox: 0, pending: 1 });
  });

  test('documents sent BY team email user should appear in team context', async ({ page }) => {
    const { team, owner } = await seedTeam({ createTeamMembers: 1 });

    const teamEmailHolder = owner;

    await seedTeamEmail({
      email: teamEmailHolder.email,
      teamId: team.id,
    });

    const { user: externalUser, team: externalTeam } = await seedUser();

    // Team email holder sends multiple documents
    await seedDocuments([
      {
        sender: teamEmailHolder,
        teamId: team.id,
        recipients: [externalUser],
        type: DocumentStatus.PENDING,
        documentOptions: { title: 'Sent by Holder Pending' },
      },
      {
        sender: teamEmailHolder,
        teamId: team.id,
        recipients: [externalUser],
        type: DocumentStatus.COMPLETED,
        documentOptions: { title: 'Sent by Holder Completed' },
      },
    ]);

    // Noise: external user's own docs (should NOT appear in team context)
    await seedDraftDocument(externalUser, externalTeam.id, [], {
      createDocumentOptions: { title: 'External Own Draft' },
    });

    const member = await seedTeamMember({ teamId: team.id, role: TeamMemberRole.MEMBER });

    await apiSignin({
      page,
      email: member.email,
      redirectPath: `/t/${team.url}/documents`,
    });

    await checkDocumentTabCount(page, 'All', 2);
    await expect(page.getByRole('link', { name: 'Sent by Holder Pending' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Sent by Holder Completed' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'External Own Draft', exact: true })).not.toBeVisible();
  });
});

test.describe('Find Documents UI - Data Isolation & No Leaking', () => {
  test('user cannot see another user personal documents via any status tab', async ({ page }) => {
    const { user: userA, team: teamA } = await seedUser();
    const { user: userB, team: teamB } = await seedUser();

    // UserA has their own docs (positive control to verify the page works)
    await seedDraftDocument(userA, teamA.id, [], {
      createDocumentOptions: { title: 'A Own Draft' },
    });
    await seedPendingDocument(userA, teamA.id, [userA], {
      createDocumentOptions: { title: 'A Own Pending' },
    });
    await seedCompletedDocument(userA, teamA.id, [userA], {
      createDocumentOptions: { title: 'A Own Completed' },
    });

    // UserB has their own docs (noise — should NOT appear for userA)
    await seedDocuments([
      {
        sender: userB,
        teamId: teamB.id,
        recipients: [],
        type: DocumentStatus.DRAFT,
        documentOptions: { title: 'B Draft Private' },
      },
      {
        sender: userB,
        teamId: teamB.id,
        recipients: [userB],
        type: DocumentStatus.PENDING,
        documentOptions: { title: 'B Pending Private' },
      },
      {
        sender: userB,
        teamId: teamB.id,
        recipients: [userB],
        type: DocumentStatus.COMPLETED,
        documentOptions: { title: 'B Completed Private' },
      },
    ]);

    await apiSignin({
      page,
      email: userA.email,
      redirectPath: `/t/${teamA.url}/documents`,
    });

    // UserA should see only their own docs
    await checkDocumentCounts(page, { draft: 1, completed: 1, all: 3 });

    // Verify no B docs leaked
    await expect(page.getByRole('link', { name: 'A Own Draft' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'B Draft Private', exact: true })).not.toBeVisible();
    await expect(page.getByRole('link', { name: 'B Pending Private', exact: true })).not.toBeVisible();
    await expect(page.getByRole('link', { name: 'B Completed Private', exact: true })).not.toBeVisible();
  });

  test('team member cannot see documents from another team via search', async ({ page }) => {
    const { team: teamA, owner: ownerA } = await seedTeam();
    const { team: teamB, owner: ownerB } = await seedTeam();

    const memberA = await seedTeamMember({ teamId: teamA.id, role: TeamMemberRole.MEMBER });

    // TeamA has a doc with "Super Secret" in the title (positive control)
    await seedDocuments([
      {
        sender: ownerA,
        teamId: teamA.id,
        recipients: [],
        type: DocumentStatus.COMPLETED,
        documentOptions: {
          title: 'Super Secret TeamA Document',
          visibility: DocumentVisibility.EVERYONE,
        },
      },
    ]);

    // TeamB has a doc with "Super Secret" in the title (should NOT appear)
    await seedDocuments([
      {
        sender: ownerB,
        teamId: teamB.id,
        recipients: [],
        type: DocumentStatus.COMPLETED,
        documentOptions: {
          title: 'Super Secret TeamB Document',
          visibility: DocumentVisibility.EVERYONE,
        },
      },
    ]);

    await apiSignin({
      page,
      email: memberA.email,
      redirectPath: `/t/${teamA.url}/documents`,
    });

    await page.getByPlaceholder('Search documents...').fill('Super Secret');
    await page.waitForURL(/query=Super/);

    // Should find the TeamA doc but NOT the TeamB doc
    await checkDocumentTabCount(page, 'All', 1);
    await expect(page.getByRole('link', { name: 'Super Secret TeamA Document' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Super Secret TeamB Document', exact: true })).not.toBeVisible();
  });

  test('search by recipient name should respect team visibility', async ({ page }) => {
    const { user: owner, organisation, team } = await seedUser();

    const [adminUser, memberUser] = await seedOrganisationMembers({
      organisationId: organisation.id,
      members: [
        { organisationRole: OrganisationMemberRole.ADMIN },
        { organisationRole: OrganisationMemberRole.MEMBER },
      ],
    });

    const { user: uniqueRecipient } = await seedUser({ name: 'Very Unique Recipient Name' });

    await seedDocuments([
      {
        sender: owner,
        teamId: team.id,
        recipients: [uniqueRecipient],
        type: DocumentStatus.COMPLETED,
        documentOptions: {
          title: 'Admin Doc with Unique Recipient',
          visibility: DocumentVisibility.ADMIN,
        },
      },
    ]);

    // Admin can find by recipient name
    await apiSignin({
      page,
      email: adminUser.email,
      redirectPath: `/t/${team.url}/documents`,
    });
    await page.getByPlaceholder('Search documents...').fill('Very Unique Recipient');
    await page.waitForURL(/query=Very/);
    await checkDocumentTabCount(page, 'All', 1);
    await apiSignout({ page });

    // Member cannot find by recipient name (visibility blocks it)
    await apiSignin({
      page,
      email: memberUser.email,
      redirectPath: `/t/${team.url}/documents`,
    });
    await page.getByPlaceholder('Search documents...').fill('Very Unique Recipient');
    await page.waitForURL(/query=Very/);
    await checkDocumentTabCount(page, 'All', 0);
    await apiSignout({ page });
  });

  test('outside user does NOT see cross-team received docs in their personal context', async ({ page }) => {
    // The UI always uses the team code path (findTeamDocumentsFilter) which filters by teamId.
    // Documents from team.id will NOT appear in outsideTeam's context.
    const { team, owner } = await seedTeam();
    const { user: outsideUser, team: outsideTeam } = await seedUser();
    const { user: otherUser } = await seedUser();

    // Team doc sent to outside user (lives on team.id, NOT outsideTeam.id)
    await seedDocuments([
      {
        sender: owner,
        teamId: team.id,
        recipients: [outsideUser],
        type: DocumentStatus.PENDING,
        documentOptions: {
          title: 'Team Doc For Outside User',
          visibility: DocumentVisibility.ADMIN,
        },
      },
    ]);

    // Team doc NOT sent to outside user (noise)
    await seedDocuments([
      {
        sender: owner,
        teamId: team.id,
        recipients: [otherUser],
        type: DocumentStatus.PENDING,
        documentOptions: {
          title: 'Team Doc For Other User Only',
          visibility: DocumentVisibility.ADMIN,
        },
      },
    ]);

    // Outside user has their own draft (positive control)
    await seedDraftDocument(outsideUser, outsideTeam.id, [], {
      createDocumentOptions: { title: 'Outside Own Draft' },
    });

    await apiSignin({
      page,
      email: outsideUser.email,
      redirectPath: `/t/${outsideTeam.url}/documents`,
    });

    // Only the outside user's own draft should appear (cross-team docs are not visible).
    // Inbox is 0 since there is no team email.
    await checkDocumentCounts(page, { inbox: 0, all: 1 });
    await expect(page.getByRole('link', { name: 'Outside Own Draft' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Team Doc For Outside User', exact: true })).not.toBeVisible();
    await expect(page.getByRole('link', { name: 'Team Doc For Other User Only', exact: true })).not.toBeVisible();
  });
});

test.describe('Find Documents UI - Tab Counts Consistency', () => {
  test('personal context tab counts should be accurate', async ({ page }) => {
    // In the UI, personal team uses findTeamDocumentsFilter (team code path).
    // Only docs with teamId = ownerTeam.id are shown.
    // Docs sent TO owner by other users live on the sender's team and won't appear.
    // Without a teamEmail, INBOX returns 0.
    const { user: owner, team: ownerTeam } = await seedUser();
    const { user: sender, team: senderTeam } = await seedUser();
    const { user: recipient } = await seedUser();

    // Owner's own documents (all on ownerTeam)
    await seedDraftDocument(owner, ownerTeam.id, [], {
      createDocumentOptions: { title: 'My Draft 1' },
    });
    await seedDraftDocument(owner, ownerTeam.id, [], {
      createDocumentOptions: { title: 'My Draft 2' },
    });
    await seedPendingDocument(owner, ownerTeam.id, [recipient], {
      createDocumentOptions: { title: 'My Pending 1' },
    });
    await seedCompletedDocument(owner, ownerTeam.id, [recipient], {
      createDocumentOptions: { title: 'My Completed 1' },
    });

    // Documents sent TO owner (these live on senderTeam, NOT ownerTeam — won't appear)
    await seedPendingDocument(sender, senderTeam.id, [owner], {
      createDocumentOptions: { title: 'Received Pending 1' },
    });
    await seedCompletedDocument(sender, senderTeam.id, [owner], {
      createDocumentOptions: { title: 'Received Completed 1' },
    });

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${ownerTeam.url}/documents`,
    });

    // Only owner's own docs appear (received docs are on sender's team).
    // Inbox is 0 since there is no team email, and only the owned completed
    // doc counts (received is on sender's team). All = 2 drafts + 1 pending + 1 completed.
    await checkDocumentCounts(page, { inbox: 0, draft: 2, pending: 1, completed: 1, all: 4 });
  });

  test('team context tab counts should be accurate with mixed documents', async ({ page }) => {
    const { team, owner } = await seedTeam({ createTeamMembers: 2 });

    const member1 = (
      await prisma.organisation.findFirstOrThrow({
        where: { teams: { some: { id: team.id } } },
        include: { members: { include: { user: true } } },
      })
    ).members[1].user;

    const { user: outsideUser, team: outsideTeam } = await seedUser();

    await seedDocuments([
      {
        sender: owner,
        teamId: team.id,
        recipients: [],
        type: DocumentStatus.DRAFT,
        documentOptions: { title: 'Team Draft 1' },
      },
      {
        sender: member1,
        teamId: team.id,
        recipients: [],
        type: DocumentStatus.DRAFT,
        documentOptions: { title: 'Team Draft 2' },
      },
      {
        sender: owner,
        teamId: team.id,
        recipients: [outsideUser],
        type: DocumentStatus.PENDING,
        documentOptions: { title: 'Team Pending 1' },
      },
      {
        sender: owner,
        teamId: team.id,
        recipients: [outsideUser],
        type: DocumentStatus.COMPLETED,
        documentOptions: { title: 'Team Completed 1' },
      },
    ]);

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${team.url}/documents`,
    });

    await checkDocumentCounts(page, { draft: 2, pending: 1, completed: 1, all: 4 });
  });

  test('team with team email tab counts should include received documents', async ({ page }) => {
    const { team, owner } = await seedTeam();

    const teamEmail = `team-count-${team.id}@test.documenso.com`;
    await seedTeamEmail({ email: teamEmail, teamId: team.id });

    const { user: external1, team: ext1Team } = await seedUser();
    const { user: external2, team: ext2Team } = await seedUser();

    // Team's own documents
    await seedDraftDocument(owner, team.id, [], {
      createDocumentOptions: { title: 'Own Draft' },
    });
    await seedPendingDocument(owner, team.id, [external1], {
      createDocumentOptions: { title: 'Own Pending' },
    });

    // Documents sent TO team email
    await seedPendingDocument(external1, ext1Team.id, [teamEmail], {
      createDocumentOptions: { title: 'Received Pending via Email' },
    });
    await seedCompletedDocument(external2, ext2Team.id, [teamEmail], {
      createDocumentOptions: { title: 'Received Completed via Email' },
    });

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${team.url}/documents`,
    });

    // Inbox = one pending doc received by team email (NOT_SIGNED), pending = own
    // pending, completed = received completed via email, all = all of the above.
    await checkDocumentCounts(page, { inbox: 1, draft: 1, pending: 1, completed: 1, all: 4 });
  });
});

test.describe('Find Documents UI - Sender Filter', () => {
  test('sender filter should narrow results correctly', async ({ page }) => {
    const { team, owner } = await seedTeam({ createTeamMembers: 2 });

    const org = await prisma.organisation.findFirstOrThrow({
      where: { teams: { some: { id: team.id } } },
      include: { members: { include: { user: true }, orderBy: { id: 'asc' } } },
    });

    const member1 = org.members[1].user;
    const member2 = org.members[2].user;

    const { user: outsideUser } = await seedUser();

    await seedDocuments([
      {
        sender: owner,
        teamId: team.id,
        recipients: [outsideUser],
        type: DocumentStatus.PENDING,
        documentOptions: { title: 'Owner Sent Doc' },
      },
      {
        sender: member1,
        teamId: team.id,
        recipients: [outsideUser],
        type: DocumentStatus.PENDING,
        documentOptions: { title: 'Member1 Sent Doc' },
      },
      {
        sender: member2,
        teamId: team.id,
        recipients: [],
        type: DocumentStatus.DRAFT,
        documentOptions: { title: 'Member2 Draft Doc' },
      },
    ]);

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${team.url}/documents`,
    });

    // Unfiltered: 3 docs total
    await checkDocumentTabCount(page, 'All', 3);

    // Filter by member1
    await toggleDocumentSenderFilter(page, member1.name ?? '');

    // Should only show member1's doc
    await checkDocumentTabCount(page, 'All', 1);
    await expect(page.getByRole('link', { name: 'Member1 Sent Doc' })).toBeVisible();
  });
});

test.describe('Find Documents UI - Rejected and Expired Tabs', () => {
  const PAST = new Date(Date.now() - 24 * 60 * 60 * 1000);

  test('rejected tab lists rejected documents and counts them independently', async ({ page }) => {
    const { user: owner, team } = await seedUser();
    const { user: recipient } = await seedUser();

    // A rejected document: envelope status REJECTED + a recipient who rejected.
    const rejectedDoc = await seedPendingDocument(owner, team.id, [recipient], {
      createDocumentOptions: { title: 'Rejected Doc' },
    });
    await prisma.envelope.update({
      where: { id: rejectedDoc.id },
      data: { status: DocumentStatus.REJECTED },
    });
    await prisma.recipient.updateMany({
      where: { envelopeId: rejectedDoc.id },
      data: { signingStatus: SigningStatus.REJECTED },
    });

    // A plain pending document (noise — must not appear under Rejected).
    await seedPendingDocument(owner, team.id, [recipient], {
      createDocumentOptions: { title: 'Plain Pending Doc' },
    });

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${team.url}/documents`,
    });

    await checkDocumentTabCount(page, 'Rejected', 1);
    await expect(page.getByRole('link', { name: 'Rejected Doc' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Plain Pending Doc' })).not.toBeVisible();
  });

  test('expired tab lists documents with an expired recipient and shows empty state otherwise', async ({ page }) => {
    const { user: owner, team } = await seedUser();
    const { user: recipient } = await seedUser();

    const expiredDoc = await seedPendingDocument(owner, team.id, [recipient], {
      createDocumentOptions: { title: 'Expired Doc' },
    });
    await prisma.recipient.updateMany({
      where: { envelopeId: expiredDoc.id },
      data: { expiresAt: PAST },
    });

    // Active pending doc — recipient link not expired.
    await seedPendingDocument(owner, team.id, [recipient], {
      createDocumentOptions: { title: 'Active Doc' },
    });

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${team.url}/documents`,
    });

    // Expired doc is still PENDING, so it appears under both Pending and Expired.
    await checkDocumentTabCount(page, 'Pending', 2);
    await checkDocumentTabCount(page, 'Expired', 1);
    await expect(page.getByRole('link', { name: 'Expired Doc' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Active Doc' })).not.toBeVisible();
  });

  test('expired tab excludes signed and CC recipients', async ({ page }) => {
    const { user: owner, team } = await seedUser();
    const { user: recipient } = await seedUser();

    // Expired but already signed — must NOT count as expired.
    const signedDoc = await seedPendingDocument(owner, team.id, [recipient], {
      createDocumentOptions: { title: 'Expired Signed Doc' },
    });
    await prisma.recipient.updateMany({
      where: { envelopeId: signedDoc.id },
      data: { expiresAt: PAST, signingStatus: SigningStatus.SIGNED },
    });

    // Expired but CC — must NOT count as expired.
    const ccDoc = await seedPendingDocument(owner, team.id, [recipient], {
      createDocumentOptions: { title: 'Expired CC Doc' },
    });
    await prisma.recipient.updateMany({
      where: { envelopeId: ccDoc.id },
      data: { expiresAt: PAST, role: RecipientRole.CC },
    });

    // Expired, unsigned, non-CC — the only one that should appear.
    const validDoc = await seedPendingDocument(owner, team.id, [recipient], {
      createDocumentOptions: { title: 'Expired Valid Doc' },
    });
    await prisma.recipient.updateMany({
      where: { envelopeId: validDoc.id },
      data: { expiresAt: PAST },
    });

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${team.url}/documents`,
    });

    await checkDocumentTabCount(page, 'Expired', 1);
    await expect(page.getByRole('link', { name: 'Expired Valid Doc' })).toBeVisible();
    await expect(page.getByRole('link', { name: 'Expired Signed Doc' })).not.toBeVisible();
    await expect(page.getByRole('link', { name: 'Expired CC Doc' })).not.toBeVisible();
  });

  test('rejected and expired tabs show tailored empty states when nothing matches', async ({ page }) => {
    const { user: owner, team } = await seedUser();
    const { user: recipient } = await seedUser();

    await seedPendingDocument(owner, team.id, [recipient], {
      createDocumentOptions: { title: 'Just Pending' },
    });

    await apiSignin({
      page,
      email: owner.email,
      redirectPath: `/t/${team.url}/documents`,
    });

    // count === 0 asserts the empty-document-state is visible.
    await checkDocumentTabCount(page, 'Rejected', 0);
    await checkDocumentTabCount(page, 'Expired', 0);
  });
});
