import { describe, test, expect, vi } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import { userEvent } from '@testing-library/user-event';
import {
  AppStateProvider,
  type Draft,
  type Insights,
  useAppStateDispatch,
  useDraft,
  useDrupal,
  useInsights,
} from '../Context.js';
import DraftManager from './DraftManager.js';
import createDraftResponse from '../../../tests/fixtures/api/post-get-draft-writing-assistant-200.json' with { type: 'json' };

describe('DraftManager', () => {
  describe('Draft Creation', () => {
    test('Creates a draft and links it when no draft ID exists', async () => {
      const initialState = {
        accountId: '12345',
        drupal: {
          entity: {
            id: 1,
            type: 'canvas_page',
          },
          draftLinked: false,
        },
      };
      const isLoading = vi.fn();
      const hasError = vi.fn();

      let draft: Draft;
      let drupal: { draftLinked?: boolean };
      const ContextCapture = () => {
        draft = useDraft();
        drupal = useDrupal();
        return null;
      };
      render(
        <AppStateProvider initialState={initialState}>
          <DraftManager isLoading={isLoading} hasError={hasError} />
          <ContextCapture />
        </AppStateProvider>,
      );

      await waitFor(() => {
        expect(draft.id).toBe(createDraftResponse.id);
        expect(drupal.draftLinked).toBe(true);
      });
      expect(isLoading).toHaveBeenCalled();
    });

    test('When draft.id exists Draft is not created', async () => {
      let draft: Draft;
      const ContextCapture = () => {
        draft = useDraft();
        return null;
      };
      render(
        <AppStateProvider initialState={{ draft: { id: 'existing-draft-id-123' } }}>
          <DraftManager />
          <ContextCapture />
        </AppStateProvider>,
      );

      await waitFor(() => {
        expect(draft.id).toBe('existing-draft-id-123');
      });
    });
  });

  describe('Draft Linking with Drupal Entity', () => {
    test('Links draft with Drupal entity when draft.id exists and draftLinked is false', async () => {
      const initialState = {
        accountId: '12345',
        draft: {
          id: 'existing-draft-id-123',
        },
        drupal: {
          entity: {
            id: 1,
            type: 'canvas_page',
          },
          draftLinked: false,
        },
      };

      let drupal: { draftLinked?: boolean };
      const ContextCapture = () => {
        drupal = useDrupal();
        return null;
      };

      render(
        <AppStateProvider initialState={initialState}>
          <DraftManager />
          <ContextCapture />
        </AppStateProvider>,
      );

      await waitFor(() => {
        expect(drupal.draftLinked).toBe(true);
      });
    });

    test('does not link draft when entity.id is invalid', async () => {
      const initialState = {
        accountId: '12345',
        draft: {
          id: 'existing-draft-123',
        },
        drupal: {
          entity: {
            id: 0,
            type: 'canvas_page',
          },
          draftLinked: false,
        },
      };

      let drupal: { draftLinked?: boolean };
      const ContextCapture = () => {
        drupal = useDrupal();
        return null;
      };
      render(
        <AppStateProvider initialState={initialState}>
          <DraftManager />
          <ContextCapture />
        </AppStateProvider>,
      );

      await waitFor(() => {
        expect(drupal.draftLinked).toBe(false);
      });
    });
  });

  describe('Draft Update', () => {
    test('updates draft when draft.id, lastUpdated exist', async () => {
      const user = userEvent.setup();

      const initialState = {
        accountId: '12345',
        draft: {
          id: 'existing-draft-123',
          lastUpdated: 1760026532,
        },
        drupal: {
          entity: {
            id: 1,
            type: 'canvas_page',
          },
          draftLinked: true,
        },
      };

      let draft: Draft;
      const ContextCapture = () => {
        draft = useDraft();
        const dispatch = useAppStateDispatch();
        return (
          <button
            onClick={() =>
              dispatch({
                type: 'updateDraft',
                draft: {
                  title: 'New title',
                },
              })
            }
          >
            Update draft
          </button>
        );
      };
      render(
        <AppStateProvider initialState={initialState}>
          <DraftManager />
          <ContextCapture />
        </AppStateProvider>,
      );

      await waitFor(() => {
        expect(draft.id).toBe('existing-draft-123');
        expect(draft.title).toBe('Untitled Canvas draft');
        expect(draft.lastUpdated).toBe(1760026532);
      });

      const updateButton = screen.getByRole('button', { name: /update draft/i });
      await user.click(updateButton);

      await waitFor(
        () => {
          expect(draft.title).toBe('New title');
          expect(draft.lastUpdated).toBe(1760088081);
        },
        {
          timeout: 3000,
        },
      );
    });
  });

  describe('Content Insights', () => {
    test('requests content insights when draft.id exists', async () => {
      const initialState = {
        accountId: '12345',
        draft: {
          id: 'existing-draft-123',
          lastUpdated: 1760026532,
        },
        drupal: {
          entity: {
            id: 1,
            type: 'canvas_page',
          },
          draftLinked: true,
        },
        keywords: ['test keyword', 'seo'],
        rankSource: {
          id: 1,
          description: 'Google US',
          isoLocale: 'en-US',
        },
        competitorUrls: ['https://example.com'],
      };

      let insights: Insights = {};
      const ContextCapture = () => {
        insights = useInsights();
        return null;
      };

      render(
        <AppStateProvider initialState={initialState}>
          <DraftManager />
          <ContextCapture />
        </AppStateProvider>,
      );

      await waitFor(
        () => {
          const loadingSpinner = screen.queryByRole('status');
          expect(loadingSpinner).not.toBeInTheDocument();
        },
        {
          timeout: 3000,
        },
      );

      await waitFor(
        () => {
          expect(insights.generatedTime).toBe(1766599194681);
        },
        { timeout: 3000 },
      );
    });
  });
});
