import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import { ThemeProvider } from 'styled-components';
import DocumentStoragePage from './DocumentStoragePage';
import { AuthContext } from '../../contexts/AuthContext';
import { AccountContext } from '../../contexts/AccountContext';
import { Account } from '../../data';
import { resetSubscriptionCache } from '../../hooks/useSubscription';

const mockGet = jest.fn();
const mockPost = jest.fn();
const mockPatch = jest.fn();
const mockDelete = jest.fn();

jest.mock('../../../axiosApi', () => ({
  axiosInstance: {
    get: (...args: unknown[]) => mockGet(...args),
    post: (...args: unknown[]) => mockPost(...args),
    patch: (...args: unknown[]) => mockPatch(...args),
    delete: (...args: unknown[]) => mockDelete(...args),
    defaults: { headers: { common: {} as Record<string, string | null> } },
  },
  applyAccessToken: jest.fn(),
}));

jest.mock('../../components/ParticleBackground/ParticleBackground', () => () => null);
jest.mock('../../components/Header2/Header2', () => () => null);

const theme = {
  main: '#4a90e2',
  focus: '#224466',
  darkMode: true,
  colors: {
    text: '#ffffff',
    cardBackground: 'rgba(0,0,0,0.3)',
    cardBorder: 'rgba(255,255,255,0.1)',
  },
};

const subscriptionResponse = (rag: boolean) => ({
  data: {
    plan: {
      slug: rag ? 'pro' : 'standard',
      name: rag ? 'Pro' : 'Standard',
      features: {
        text_generation: true,
        image_generation: rag,
        rag,
        all_future_features: false,
      },
    },
    status: 'active',
    source: 'stripe',
    needs_checkout: false,
    stripe_subscription_id: 'sub_1',
    usage: {},
  },
});

const mockGetByUrl = (overrides: { rag: boolean }) => {
  mockGet.mockImplementation((url: string) => {
    if (url === '/monetization/subscription/') {
      return Promise.resolve(subscriptionResponse(overrides.rag));
    }
    if (typeof url === 'string' && url.startsWith('/documents/')) {
      return Promise.resolve({
        data: { count: 0, page: 1, page_size: 20, scope: 'personal', results: [] },
      });
    }
    if (url === '/drive/connections/') {
      return Promise.resolve({ data: [] });
    }
    return Promise.resolve({ data: [] });
  });
};

const renderPage = (options?: { isCompanyManager?: boolean; hasCompany?: boolean }) => {
  const isCompanyManager = options?.isCompanyManager ?? false;
  const hasCompany = options?.hasCompany ?? false;
  const account = new Account({
    email: 'user@example.com',
    is_company_manager: isCompanyManager,
    company: hasCompany ? { id: 1, name: 'Acme', state: '', zipcode: '', address: '' } : undefined,
  });
  return render(
    <MemoryRouter initialEntries={['/document_storage/']}>
      <ThemeProvider theme={theme as never}>
        <AuthContext.Provider
          value={{
            authenticated: true,
            setAuthentication: jest.fn(),
            needsNewPassword: false,
            setNeedsNewPassword: jest.fn(),
            loading: false,
          }}
        >
          <AccountContext.Provider value={{ account, setAccount: jest.fn() }}>
            <DocumentStoragePage />
          </AccountContext.Provider>
        </AuthContext.Provider>
      </ThemeProvider>
    </MemoryRouter>
  );
};

describe('DocumentStoragePage (#81/#82/#83/#84/#93)', () => {
  beforeEach(() => {
    mockGet.mockReset();
    mockPost.mockReset();
    mockPatch.mockReset();
    mockDelete.mockReset();
    resetSubscriptionCache();
  });

  it('shows an upgrade card instead of upload tables when the plan has no RAG', async () => {
    mockGetByUrl({ rag: false });

    renderPage();

    expect(await screen.findByText('Unlock document storage')).toBeInTheDocument();
    expect(screen.getByRole('link', { name: /upgrade in billing/i })).toHaveAttribute(
      'href',
      '/account/'
    );
    expect(screen.queryByText('Company documents')).not.toBeInTheDocument();
    expect(screen.queryByText('Personal documents')).not.toBeInTheDocument();
    expect(screen.queryByText('Upload a Document')).not.toBeInTheDocument();
  });

  it('shows personal documents for users without a company', async () => {
    mockGetByUrl({ rag: true });

    renderPage({ hasCompany: false });

    expect(await screen.findByText('Personal documents')).toBeInTheDocument();
    expect(screen.queryByText('Company documents')).not.toBeInTheDocument();
    expect(screen.queryByRole('tab', { name: 'Company' })).not.toBeInTheDocument();
    expect(
      screen.queryByText(/shared with your whole company workspace/i)
    ).not.toBeInTheDocument();
    expect(screen.getByText('Upload a Document')).toBeInTheDocument();
    expect(screen.getByText('Cloud drives')).toBeInTheDocument();
    expect(screen.queryByText('Company knowledge sources')).not.toBeInTheDocument();
  });

  it('shows company/personal tabs and company helper copy for company members', async () => {
    mockGetByUrl({ rag: true });

    renderPage({ hasCompany: true });

    expect(await screen.findByText('Company documents')).toBeInTheDocument();
    expect(screen.getByRole('tab', { name: 'Personal' })).toBeInTheDocument();
    expect(screen.getByRole('tab', { name: 'Company' })).toBeInTheDocument();
    expect(screen.getByText(/shared with your whole company workspace/i)).toBeInTheDocument();
  });

  it('also shows the company knowledge sources section for company managers (#84)', async () => {
    mockGetByUrl({ rag: true });

    renderPage({ isCompanyManager: true, hasCompany: true });

    expect(await screen.findByText('Company knowledge sources')).toBeInTheDocument();
  });

  it('requests documents with workspace/page/search params (#93)', async () => {
    mockGetByUrl({ rag: true });

    renderPage({ hasCompany: true });

    await screen.findByText('Company documents');
    await waitFor(() => {
      expect(mockGet).toHaveBeenCalledWith(
        '/documents/',
        expect.objectContaining({
          params: expect.objectContaining({
            workspace: 'company',
            page: 1,
            page_size: 20,
          }),
        })
      );
    });
  });
});
