import React from "react";
import "@testing-library/jest-dom";
import { fireEvent, render, screen, waitFor } from "@testing-library/react";

import AiWorkspacePanel from "./components/AiWorkspacePanel";
import Markdown from "./components/Markdown";
import { ToastProvider } from "./toast";
import { api } from "./api";
import { AccountPlanProvider } from "./accountPlan";

jest.mock("./api", () => ({
  api: {
    get: jest.fn(),
    post: jest.fn(),
    delete: jest.fn(),
    interceptors: { request: { use: jest.fn() }, response: { use: jest.fn() } },
  },
  getApiErrorMessage: (_e: any, fallback?: string) => fallback || "Request failed.",
}));

const mockedApi = api as jest.Mocked<typeof api>;

function renderPanel() {
  return render(
    <ToastProvider>
      <AiWorkspacePanel jobId={7} />
    </ToastProvider>,
  );
}

beforeEach(() => {
  jest.clearAllMocks();
  mockedApi.get.mockImplementation((url: string) => {
    if (url.includes("/modules")) return Promise.resolve({ data: { modules: [], provider: "gemini" } } as any);
    if (url === "/ai/usage") return Promise.resolve({ data: { currentMonth: { calls: 3, inputCharacters: 100, outputCharacters: 50, estimatedTokens: 38 }, allTime: { calls: 8, inputCharacters: 300, outputCharacters: 120, estimatedTokens: 105 } } } as any);
    return Promise.resolve({ data: [] } as any); // history
  });
});

test("shows transparent monthly usage", async () => {
  renderPanel();
  expect(await screen.findByText(/approximately/)).toHaveTextContent("3 runs");
  expect(screen.getByText(/approximately/)).toHaveTextContent("38 tokens");
});

test("renders modules and generates a suggestion into history", async () => {
  mockedApi.post.mockResolvedValueOnce({
    data: { id: 1, module: "job-analysis", mode: null, title: "Job analysis", provider: "gemini", result: { text: "**Company**\nAcme" }, createdAtUtc: new Date().toISOString() },
  } as any);

  renderPanel();

  fireEvent.click(await screen.findByRole("button", { name: /Generate/i }));

  await waitFor(() => expect(mockedApi.post).toHaveBeenCalledWith("/jobapplications/7/ai/generate", expect.objectContaining({ module: "job-analysis" })));
  expect(await screen.findByText("Acme")).toBeInTheDocument();
});

test("cover letter sends the selected mode", async () => {
  mockedApi.post.mockResolvedValueOnce({
    data: { id: 2, module: "cover-letter", mode: "professional", title: "Cover letter · Professional", provider: "p", result: { text: "Dear team" }, createdAtUtc: new Date().toISOString() },
  } as any);

  renderPanel();
  fireEvent.click(await screen.findByText("Cover Letter"));
  fireEvent.click(screen.getByRole("button", { name: /Generate/i }));

  await waitFor(() => expect(mockedApi.post).toHaveBeenCalledWith("/jobapplications/7/ai/generate", expect.objectContaining({ module: "cover-letter", mode: "professional" })));
});

test("free users see a locked state and cannot start generation", async () => {
  render(
    <ToastProvider>
      <AccountPlanProvider value={{ plan: "free", canUseAi: false, canUseProThemes: false }}>
        <AiWorkspacePanel jobId={7} />
      </AccountPlanProvider>
    </ToastProvider>,
  );

  expect(await screen.findByText(/Build application drafts with Pro/)).toBeInTheDocument();
  expect(screen.getByRole("link", { name: "View Pro" })).toHaveAttribute("href", "/settings");
  expect(screen.getByRole("button", { name: "Pro required" })).toBeDisabled();
  expect(mockedApi.post).not.toHaveBeenCalled();
});

test("Markdown renders headings, bold, and bullet lists", () => {
  render(<Markdown text={"# Title\n**Strengths**\n- one\n- two\nplain *word*"} />);
  expect(screen.getByText("Title")).toBeInTheDocument();
  expect(screen.getByText("Strengths")).toBeInTheDocument();
  expect(screen.getByText("one")).toBeInTheDocument();
  expect(screen.getByText("two")).toBeInTheDocument();
});
