import type { AppContextValue } from '@/context/app-context'
import type { ICurrentWorkspace, Member } from '@/models/common'
import { screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { vi } from 'vitest'
import { createMockProviderContextValue } from '@/__mocks__/provider-context'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { Plan } from '@/app/components/billing/type'
import { useAppContext } from '@/context/app-context'
import { useProviderContext } from '@/context/provider-context'
import { useFormatTimeFromNow } from '@/hooks/use-format-time-from-now'
import { useMembers } from '@/service/use-common'
import MembersPage from '../index'

vi.mock('@/context/app-context')
vi.mock('@/context/provider-context')
vi.mock('@/hooks/use-format-time-from-now')
vi.mock('@/service/use-common')

const renderMembersPage = () => renderWithSystemFeatures(<MembersPage />, {
  systemFeatures: { is_email_setup: true },
})

vi.mock('../edit-workspace-modal', () => ({
  default: ({ onCancel }: { onCancel: () => void }) => (
    <div>
      <div>Edit Workspace Modal</div>
      <button onClick={onCancel}>Close Edit Workspace</button>
    </div>
  ),
}))
vi.mock('../invite-button', () => ({
  default: ({ onClick, disabled }: { onClick: () => void, disabled: boolean }) => (
    <button onClick={onClick} disabled={disabled}>Invite</button>
  ),
}))
vi.mock('../invite-modal', () => ({
  default: ({ onCancel, onSend }: { onCancel: () => void, onSend: (results: Array<{ email: string, status: 'success', url: string }>) => void }) => (
    <div>
      <div>Invite Modal</div>
      <button onClick={onCancel}>Close Invite Modal</button>
      <button onClick={() => onSend([{ email: 'sent@example.com', status: 'success', url: 'http://invite/link' }])}>Send Invite Results</button>
    </div>
  ),
}))
vi.mock('../invited-modal', () => ({
  default: ({ onCancel }: { onCancel: () => void }) => (
    <div>
      <div>Invited Modal</div>
      <button onClick={onCancel}>Close Invited Modal</button>
    </div>
  ),
}))
vi.mock('../operation', () => ({
  default: ({ member }: { member: Member }) => (
    <div>
      Member Operation
      {' '}
      {member.role}
    </div>
  ),
}))
vi.mock('../operation/transfer-ownership', () => ({
  default: ({ onOperate }: { onOperate: () => void }) => <button onClick={onOperate}>Transfer ownership</button>,
}))
vi.mock('../transfer-ownership-modal', () => ({
  default: ({ onClose }: { onClose: () => void }) => (
    <div>
      <div>Transfer Ownership Modal</div>
      <button onClick={onClose}>Close Transfer Modal</button>
    </div>
  ),
}))
vi.mock('@/app/components/billing/upgrade-btn', () => ({
  default: () => <div>Upgrade Button</div>,
}))

describe('MembersPage', () => {
  const mockRefetch = vi.fn()
  const mockFormatTimeFromNow = vi.fn(() => 'just now')

  const mockAccounts: Member[] = [
    {
      id: '1',
      name: 'Owner User',
      email: 'owner@example.com',
      avatar: '',
      avatar_url: '',
      role: 'owner',
      last_active_at: '1731000000',
      last_login_at: '1731000000',
      created_at: '1731000000',
      status: 'active',
    },
    {
      id: '2',
      name: 'Admin User',
      email: 'admin@example.com',
      avatar: '',
      avatar_url: '',
      role: 'admin',
      last_active_at: '1731000000',
      last_login_at: '1731000000',
      created_at: '1731000000',
      status: 'active',
    },
  ]

  beforeEach(() => {
    vi.clearAllMocks()

    vi.mocked(useAppContext).mockReturnValue({
      userProfile: { email: 'owner@example.com' },
      currentWorkspace: { name: 'Test Workspace', role: 'owner' } as ICurrentWorkspace,
      isCurrentWorkspaceOwner: true,
      isCurrentWorkspaceManager: true,
    } as unknown as AppContextValue)

    vi.mocked(useMembers).mockReturnValue({
      data: { accounts: mockAccounts },
      refetch: mockRefetch,
    } as unknown as ReturnType<typeof useMembers>)

    vi.mocked(useProviderContext).mockReturnValue(createMockProviderContextValue({
      enableBilling: false,
      isAllowTransferWorkspace: true,
    }))

    vi.mocked(useFormatTimeFromNow).mockReturnValue({
      formatTimeFromNow: mockFormatTimeFromNow,
    })
  })

  it('should render workspace and member information', () => {
    renderMembersPage()

    expect(screen.getByText('Test Workspace'))!.toBeInTheDocument()
    expect(screen.getByText('Owner User'))!.toBeInTheDocument()
    expect(screen.getByText('Admin User'))!.toBeInTheDocument()
  })

  it('should open and close invite modal', async () => {
    const user = userEvent.setup()

    renderMembersPage()

    await user.click(screen.getByRole('button', { name: /invite/i }))
    expect(screen.getByText('Invite Modal'))!.toBeInTheDocument()

    await user.click(screen.getByRole('button', { name: 'Close Invite Modal' }))
    expect(screen.queryByText('Invite Modal')).not.toBeInTheDocument()
  })

  it('should open invited modal after invite results are sent', async () => {
    const user = userEvent.setup()

    renderMembersPage()

    await user.click(screen.getByRole('button', { name: /invite/i }))
    await user.click(screen.getByRole('button', { name: 'Send Invite Results' }))

    expect(screen.getByText('Invited Modal'))!.toBeInTheDocument()
    expect(mockRefetch).toHaveBeenCalled()

    await user.click(screen.getByRole('button', { name: 'Close Invited Modal' }))
    expect(screen.queryByText('Invited Modal')).not.toBeInTheDocument()
  })

  it('should open transfer ownership modal when transfer action is used', async () => {
    const user = userEvent.setup()

    renderMembersPage()

    await user.click(screen.getByRole('button', { name: /transfer ownership/i }))
    expect(screen.getByText('Transfer Ownership Modal'))!.toBeInTheDocument()
  })

  it('should show non-interactive owner role when transfer ownership is not allowed', () => {
    vi.mocked(useProviderContext).mockReturnValue(createMockProviderContextValue({
      enableBilling: false,
      isAllowTransferWorkspace: false,
    }))

    renderMembersPage()

    expect(screen.getByText('common.members.owner'))!.toBeInTheDocument()
    expect(screen.queryByRole('button', { name: /transfer ownership/i })).not.toBeInTheDocument()
  })

  it('should hide manager controls for non-owner non-manager users', () => {
    vi.mocked(useAppContext).mockReturnValue({
      userProfile: { email: 'admin@example.com' },
      currentWorkspace: { name: 'Test Workspace', role: 'admin' } as ICurrentWorkspace,
      isCurrentWorkspaceOwner: false,
      isCurrentWorkspaceManager: false,
    } as unknown as AppContextValue)

    renderMembersPage()

    expect(screen.queryByRole('button', { name: /invite/i })).not.toBeInTheDocument()
    expect(screen.queryByText('Transfer ownership')).not.toBeInTheDocument()
  })

  it('should open and close edit workspace modal', async () => {
    const user = userEvent.setup()

    renderMembersPage()

    await user.click(screen.getByRole('button', { name: /account\.editWorkspaceInfo/i }))
    expect(screen.getByText('Edit Workspace Modal'))!.toBeInTheDocument()

    await user.click(screen.getByRole('button', { name: 'Close Edit Workspace' }))
    expect(screen.queryByText('Edit Workspace Modal')).not.toBeInTheDocument()
  })

  it('should close transfer ownership modal when close is clicked', async () => {
    const user = userEvent.setup()

    renderMembersPage()

    await user.click(screen.getByRole('button', { name: /transfer ownership/i }))
    expect(screen.getByText('Transfer Ownership Modal'))!.toBeInTheDocument()

    await user.click(screen.getByRole('button', { name: 'Close Transfer Modal' }))
    expect(screen.queryByText('Transfer Ownership Modal')).not.toBeInTheDocument()
  })

  it('should show pending status and you indicator', () => {
    const pendingAccount: Member = {
      ...mockAccounts[1]!,
      status: 'pending',
    }
    vi.mocked(useMembers).mockReturnValue({
      data: { accounts: [mockAccounts[0], pendingAccount] },
      refetch: mockRefetch,
    } as unknown as ReturnType<typeof useMembers>)

    renderMembersPage()

    expect(screen.getByText(/members\.pending/i))!.toBeInTheDocument()
    expect(screen.getByText(/members\.you/i))!.toBeInTheDocument() // Current user is owner@example.com
  })

  it('should show billing information for limited plan', () => {
    vi.mocked(useProviderContext).mockReturnValue(createMockProviderContextValue({
      enableBilling: true,
      plan: {
        type: Plan.sandbox,
        total: { teamMembers: 5 } as unknown as ReturnType<typeof useProviderContext>['plan']['total'],
      } as unknown as ReturnType<typeof useProviderContext>['plan'],
    }))

    renderMembersPage()

    expect(screen.getByText(/plansCommon\.member/i))!.toBeInTheDocument()
    expect(screen.getByText('2'))!.toBeInTheDocument() // accounts.length
    expect(screen.getByText('/'))!.toBeInTheDocument()
    expect(screen.getByText('5'))!.toBeInTheDocument() // plan.total.teamMembers
  })

  it('should show unlimited billing information', () => {
    vi.mocked(useProviderContext).mockReturnValue(createMockProviderContextValue({
      enableBilling: true,
      plan: {
        type: Plan.sandbox,
        total: { teamMembers: -1 } as unknown as ReturnType<typeof useProviderContext>['plan']['total'],
      } as unknown as ReturnType<typeof useProviderContext>['plan'],
    }))

    renderMembersPage()

    expect(screen.getByText(/plansCommon\.unlimited/i))!.toBeInTheDocument()
  })

  it('should show non-billing member format for team plan even when billing is enabled', () => {
    vi.mocked(useProviderContext).mockReturnValue(createMockProviderContextValue({
      enableBilling: true,
      plan: {
        type: Plan.team,
        total: { teamMembers: 50 } as unknown as ReturnType<typeof useProviderContext>['plan']['total'],
      } as unknown as ReturnType<typeof useProviderContext>['plan'],
    }))

    renderMembersPage()

    // Plan.team is an unlimited member plan → isNotUnlimitedMemberPlan=false → non-billing layout
    // Plan.team is an unlimited member plan → isNotUnlimitedMemberPlan=false → non-billing layout
    expect(screen.getByText(/plansCommon\.memberAfter/i))!.toBeInTheDocument()
  })

  it('should show invite button when user is manager but not owner', () => {
    vi.mocked(useAppContext).mockReturnValue({
      userProfile: { email: 'admin@example.com' },
      currentWorkspace: { name: 'Test Workspace', role: 'admin' } as ICurrentWorkspace,
      isCurrentWorkspaceOwner: false,
      isCurrentWorkspaceManager: true,
    } as unknown as AppContextValue)

    renderMembersPage()

    expect(screen.getByRole('button', { name: /invite/i }))!.toBeInTheDocument()
    expect(screen.queryByRole('button', { name: /transfer ownership/i })).not.toBeInTheDocument()
  })

  it('should allow admins to operate other non-owner members only', () => {
    vi.mocked(useAppContext).mockReturnValue({
      userProfile: { email: 'admin@example.com' },
      currentWorkspace: { name: 'Test Workspace', role: 'admin' } as ICurrentWorkspace,
      isCurrentWorkspaceOwner: false,
      isCurrentWorkspaceManager: true,
    } as unknown as AppContextValue)
    vi.mocked(useMembers).mockReturnValue({
      data: {
        accounts: [
          mockAccounts[0],
          mockAccounts[1],
          { ...mockAccounts[1]!, id: '3', email: 'editor@example.com', name: 'Editor User', role: 'editor' },
          { ...mockAccounts[1]!, id: '4', email: 'normal@example.com', name: 'Normal User', role: 'normal' },
          { ...mockAccounts[1]!, id: '5', email: 'dataset@example.com', name: 'Dataset User', role: 'dataset_operator' },
          { ...mockAccounts[1]!, id: '6', email: 'other-admin@example.com', name: 'Other Admin User', role: 'admin' },
        ],
      },
      refetch: mockRefetch,
    } as unknown as ReturnType<typeof useMembers>)

    renderMembersPage()

    expect(screen.getByText('Member Operation editor'))!.toBeInTheDocument()
    expect(screen.getByText('Member Operation normal'))!.toBeInTheDocument()
    expect(screen.getByText('Member Operation dataset_operator'))!.toBeInTheDocument()
    expect(screen.getByText('Member Operation admin'))!.toBeInTheDocument()
    expect(screen.getAllByText('common.members.admin')).toHaveLength(1)
    expect(screen.queryByText('Member Operation owner')).not.toBeInTheDocument()
  })

  it('should use created_at as fallback when last_active_at is empty', () => {
    const memberNoLastActive: Member = {
      ...mockAccounts[1]!,
      last_active_at: '',
      created_at: '1700000000',
    }
    vi.mocked(useMembers).mockReturnValue({
      data: { accounts: [memberNoLastActive] },
      refetch: mockRefetch,
    } as unknown as ReturnType<typeof useMembers>)

    renderMembersPage()

    expect(mockFormatTimeFromNow).toHaveBeenCalledWith(1700000000000)
  })

  it('should not show plural s when only one account in billing layout', () => {
    vi.mocked(useMembers).mockReturnValue({
      data: { accounts: [mockAccounts[0]] },
      refetch: mockRefetch,
    } as unknown as ReturnType<typeof useMembers>)
    vi.mocked(useProviderContext).mockReturnValue(createMockProviderContextValue({
      enableBilling: true,
      plan: {
        type: Plan.sandbox,
        total: { teamMembers: 5 } as unknown as ReturnType<typeof useProviderContext>['plan']['total'],
      } as unknown as ReturnType<typeof useProviderContext>['plan'],
    }))

    renderMembersPage()

    expect(screen.getByText(/plansCommon\.member/i))!.toBeInTheDocument()
    expect(screen.getByText('1'))!.toBeInTheDocument()
  })

  it('should not show plural s when only one account in non-billing layout', () => {
    vi.mocked(useMembers).mockReturnValue({
      data: { accounts: [mockAccounts[0]] },
      refetch: mockRefetch,
    } as unknown as ReturnType<typeof useMembers>)

    renderMembersPage()

    expect(screen.getByText(/plansCommon\.memberAfter/i))!.toBeInTheDocument()
    expect(screen.getByText('1'))!.toBeInTheDocument()
  })

  it('should show normal role as fallback for unknown role', () => {
    vi.mocked(useAppContext).mockReturnValue({
      userProfile: { email: 'admin@example.com' },
      currentWorkspace: { name: 'Test Workspace', role: 'admin' } as ICurrentWorkspace,
      isCurrentWorkspaceOwner: false,
      isCurrentWorkspaceManager: false,
    } as unknown as AppContextValue)
    vi.mocked(useMembers).mockReturnValue({
      data: { accounts: [{ ...mockAccounts[1], role: 'unknown_role' as Member['role'] }] },
      refetch: mockRefetch,
    } as unknown as ReturnType<typeof useMembers>)

    renderMembersPage()

    expect(screen.getByText('common.members.normal'))!.toBeInTheDocument()
  })

  it('should show upgrade button when member limit is full', () => {
    vi.mocked(useProviderContext).mockReturnValue(createMockProviderContextValue({
      enableBilling: true,
      plan: {
        type: Plan.sandbox,
        total: { teamMembers: 2 } as unknown as ReturnType<typeof useProviderContext>['plan']['total'],
      } as unknown as ReturnType<typeof useProviderContext>['plan'],
    }))

    renderMembersPage()

    expect(screen.getByText('Upgrade Button'))!.toBeInTheDocument()
  })
})
