import { screen, waitFor } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { renderWithProviders } from "../test/testHelpers";
import { ClientTabloPage } from "./ClientTabloPage";

const {
  apiGetMock,
  apiPostMock,
  apiPutMock,
  apiDeleteMock,
  updateTaskMock,
  insertTaskMock,
  deleteTaskMock,
  supabaseFromMock,
} = vi.hoisted(() => {
  const apiGetMock = vi.fn(async (url: string) => {
    if (url.endsWith("/brief.pdf")) {
      return {
        status: 200,
        data: { content: "test file content", contentType: "application/pdf" },
      };
    }

    return { status: 200, data: { folders: [] } };
  });
  const apiPostMock = vi.fn(async () => ({
    status: 200,
    data: {
      message: "ok",
      fileName: "brief.pdf",
      tabloId: "tablo-1",
      folder: { id: "folder-1", name: "Livrable", description: "" },
    },
  }));
  const apiPutMock = vi.fn(async () => ({
    status: 200,
    data: { folder: { id: "folder-1", name: "Livrable mis à jour", description: "Desc" } },
  }));
  const apiDeleteMock = vi.fn(async () => ({ status: 200, data: { message: "ok" } }));
  const createUpdateBuilder = () => {
    const builder = {
      error: null as null,
      eq: vi.fn(() => builder),
      select: vi.fn(() => ({
        single: async () => ({ data: { id: "task-1" }, error: null }),
      })),
    };
    return builder;
  };
  const updateTaskMock = vi.fn(() => createUpdateBuilder());
  const insertTaskMock = vi.fn(() => ({
    select: () => ({
      single: async () => ({ data: { id: "task-created" }, error: null }),
    }),
  }));
  const deleteTaskMock = vi.fn(() => ({
    eq: vi.fn(async () => ({ error: null })),
  }));
  const supabaseFromMock = vi.fn(() => ({
    insert: insertTaskMock,
    update: updateTaskMock,
    delete: deleteTaskMock,
  }));

  return {
    apiGetMock,
    apiPostMock,
    apiPutMock,
    apiDeleteMock,
    updateTaskMock,
    insertTaskMock,
    deleteTaskMock,
    supabaseFromMock,
  };
});
let latestTabloTasksSectionProps: Record<string, unknown> | null = null;
let latestEtapesSectionProps: Record<string, unknown> | null = null;
let latestRoadmapSectionProps: Record<string, unknown> | null = null;
let latestTabloFilesSectionProps: Record<string, unknown> | null = null;

vi.mock("@xtablo/shared", async (importOriginal) => {
  const actual = await importOriginal<typeof import("@xtablo/shared")>();

  return {
    ...actual,
    buildApi: () => ({
      create: () => ({
        get: apiGetMock,
        post: apiPostMock,
        put: apiPutMock,
        delete: apiDeleteMock,
      }),
    }),
  };
});

vi.mock("../lib/supabase", () => ({
  supabase: {
    from: supabaseFromMock,
  },
}));

vi.mock("@tanstack/react-query", async (importOriginal) => {
  const actual = await importOriginal<typeof import("@tanstack/react-query")>();

  return {
    ...actual,
    useQuery: ({ queryKey, queryFn }: { queryKey: string[]; queryFn?: () => Promise<unknown> }) => {
      if (queryKey[0] === "client-tablo-folders" && queryFn) {
        void queryFn();
      }
      switch (queryKey[0]) {
        case "client-tablo":
          return {
            data: {
              id: "tablo-1",
              name: "Client Project",
              color: "bg-blue-500",
              image: null,
              created_at: "2026-01-01T00:00:00.000Z",
              deleted_at: null,
              position: 0,
              status: "todo",
              user_id: "user-1",
              is_admin: false,
              access_level: "guest",
            },
            isLoading: false,
          };
        case "client-tasks":
          return {
            data: [
              {
                id: "task-1",
                title: "Prepare proposal",
                status: "todo",
                tablo_id: "tablo-1",
                assignee_id: "client-user-1",
              },
            ],
            isLoading: false,
            error: null,
          };
        case "client-etapes":
          return {
            data: [
              {
                id: "etape-1",
                title: "Kickoff",
                status: "in_progress",
                position: 0,
              },
            ],
            isLoading: false,
            error: null,
          };
        case "client-events":
        case "client-members":
        case "client-tablo-folders":
          return {
            data: [],
            isLoading: false,
            error: null,
          };
        case "client-tablo-files":
          return {
            data: { fileNames: [] },
            isLoading: false,
            error: null,
          };
        default:
          return {
            data: undefined,
            isLoading: false,
            error: null,
          };
      }
    },
  };
});

vi.mock("@xtablo/tablo-views", async (importOriginal) => {
  const actual = await importOriginal<typeof import("@xtablo/tablo-views")>();

  return {
    ...actual,
    EtapesSection: (props: Record<string, unknown>) => {
      latestEtapesSectionProps = props;
      return (
        <div>
          <div>Etapes section</div>
          <button
            type="button"
            onClick={() =>
              (
                props.onCreateTask as
                  | ((task: {
                      tablo_id: string;
                      title: string;
                      status: string;
                      parent_task_id: string;
                      is_parent: boolean;
                      position: number;
                    }) => void)
                  | undefined
              )?.({
                tablo_id: "tablo-1",
                title: "Task from etape",
                status: "todo",
                parent_task_id: "etape-1",
                is_parent: false,
                position: 0,
              })
            }
          >
            Créer tâche d'étape test
          </button>
          <button
            type="button"
            onClick={() =>
              (
                props.onTaskStatusChange as ((taskId: string, status: string) => void) | undefined
              )?.("task-1", "done")
            }
          >
            Terminer tâche d'étape test
          </button>
        </div>
      );
    },
    RoadmapSection: (props: Record<string, unknown>) => {
      latestRoadmapSectionProps = props;
      return (
        <div>
          <div>Roadmap section</div>
          <button
            type="button"
            onClick={() =>
              (
                props.onTaskStatusChange as ((taskId: string, status: string) => void) | undefined
              )?.("task-1", "done")
            }
          >
            Changer statut roadmap test
          </button>
        </div>
      );
    },
    TabloDiscussionSection: () => <div>Discussion section</div>,
    TabloEventsSection: () => <div>Events section</div>,
    TabloFilesSection: (props: Record<string, unknown>) => {
      latestTabloFilesSectionProps = props;
      return (
        <div>
          <div>Files section</div>
          <button
            type="button"
            onClick={() =>
              (
                props.onCreateFile as
                  | ((params: {
                      tabloId: string;
                      fileName: string;
                      data: { content: string; contentType: string };
                    }) => void)
                  | undefined
              )?.({
                tabloId: "tablo-1",
                fileName: "brief.pdf",
                data: {
                  content: "data:application/pdf;base64,AAAA",
                  contentType: "application/pdf",
                },
              })
            }
          >
            Créer fichier test
          </button>
          <button
            type="button"
            onClick={() =>
              (
                props.onDownloadFile as
                  | ((params: { tabloId: string; fileName: string }) => void)
                  | undefined
              )?.({ tabloId: "tablo-1", fileName: "brief.pdf" })
            }
          >
            Télécharger fichier test
          </button>
          <button
            type="button"
            onClick={() =>
              (
                props.onCreateFolder as
                  | ((params: {
                      tabloId: string;
                      name: string;
                      description: string;
                      createdBy: string;
                    }) => void)
                  | undefined
              )?.({
                tabloId: "tablo-1",
                name: "Livrable",
                description: "Desc",
                createdBy: "client-user-1",
              })
            }
          >
            Créer livrable test
          </button>
          <button
            type="button"
            onClick={() =>
              (
                props.onUpdateFolder as
                  | ((params: {
                      tabloId: string;
                      folderId: string;
                      name: string;
                      description: string;
                    }) => void)
                  | undefined
              )?.({
                tabloId: "tablo-1",
                folderId: "folder-1",
                name: "Livrable mis à jour",
                description: "Desc",
              })
            }
          >
            Modifier livrable test
          </button>
          <button
            type="button"
            onClick={() =>
              (
                props.onDeleteFolder as
                  | ((params: { tabloId: string; folderId: string; folderName: string }) => void)
                  | undefined
              )?.({
                tabloId: "tablo-1",
                folderId: "folder-1",
                folderName: "Livrable",
              })
            }
          >
            Supprimer livrable test
          </button>
        </div>
      );
    },
    TabloTasksSection: (props: Record<string, unknown>) => {
      latestTabloTasksSectionProps = props;
      return (
        <div>
          <div>Tasks section</div>
          <button
            type="button"
            onClick={() =>
              (props.onCreateTask as ((task: Record<string, unknown>) => void) | undefined)?.({
                tablo_id: "tablo-1",
                title: "Task from tasks tab",
                status: "todo",
                position: 1,
                parent_task_id: "etape-1",
                is_parent: false,
              })
            }
          >
            Créer tâche test
          </button>
          <button
            type="button"
            onClick={() =>
              (props.onUpdateTask as ((task: Record<string, unknown>) => void) | undefined)?.({
                id: "task-1",
                tablo_id: "tablo-1",
                title: "Updated task title",
              })
            }
          >
            Modifier tâche test
          </button>
          <button
            type="button"
            onClick={() =>
              (props.onDeleteTask as ((taskId: string) => void) | undefined)?.("task-1")
            }
          >
            Supprimer tâche test
          </button>
          <button
            type="button"
            onClick={() =>
              (
                props.onUpdateTaskPositions as
                  | ((updates: Array<{ id: string; position: number; status: string }>) => void)
                  | undefined
              )?.([{ id: "task-1", position: 7, status: "done" }])
            }
          >
            Déplacer la tâche test
          </button>
        </div>
      );
    },
  };
});

describe("ClientTabloPage parity shell", () => {
  beforeEach(() => {
    window.URL.createObjectURL = vi.fn(() => "blob:test");
    window.URL.revokeObjectURL = vi.fn();
    HTMLAnchorElement.prototype.click = vi.fn();
    apiGetMock.mockClear();
    apiPostMock.mockClear();
    apiPutMock.mockClear();
    apiDeleteMock.mockClear();
    updateTaskMock.mockClear();
    insertTaskMock.mockClear();
    deleteTaskMock.mockClear();
    supabaseFromMock.mockClear();
    latestTabloTasksSectionProps = null;
    latestEtapesSectionProps = null;
    latestRoadmapSectionProps = null;
    latestTabloFilesSectionProps = null;
  });

  it("requests folders from the tablo-data API route", () => {
    renderWithProviders(<ClientTabloPage />, {
      route: "/tablo/tablo-1",
      path: "/tablo/:tabloId",
    });

    expect(apiGetMock).toHaveBeenCalledWith("/api/v1/tablo-data/tablo-1/folders");
  });

  it("wires real task mutation callbacks throughout the client task surfaces", async () => {
    const { user } = renderWithProviders(<ClientTabloPage />, {
      route: "/tablo/tablo-1",
      path: "/tablo/:tabloId",
    });

    await user.click(screen.getByRole("button", { name: "Étapes" }));

    expect(latestEtapesSectionProps?.onCreateTask).toBeTypeOf("function");
    expect(latestEtapesSectionProps?.onTaskStatusChange).toBeTypeOf("function");

    await user.click(screen.getByRole("button", { name: "Créer tâche d'étape test" }));
    await user.click(screen.getByRole("button", { name: "Terminer tâche d'étape test" }));

    await user.click(screen.getByRole("button", { name: "Tâches" }));

    expect(latestTabloTasksSectionProps?.onCreateTask).toBeTypeOf("function");
    expect(latestTabloTasksSectionProps?.onUpdateTask).toBeTypeOf("function");
    expect(latestTabloTasksSectionProps?.onDeleteTask).toBeTypeOf("function");
    expect(latestTabloTasksSectionProps?.onUpdateTaskPositions).toBeTypeOf("function");

    await user.click(screen.getByRole("button", { name: "Créer tâche test" }));
    await user.click(screen.getByRole("button", { name: "Modifier tâche test" }));
    await user.click(screen.getByRole("button", { name: "Supprimer tâche test" }));
    await user.click(screen.getByRole("button", { name: "Déplacer la tâche test" }));

    await user.click(screen.getByRole("button", { name: "Roadmap" }));

    expect(latestRoadmapSectionProps?.onTaskStatusChange).toBeTypeOf("function");

    await user.click(screen.getByRole("button", { name: "Changer statut roadmap test" }));

    await waitFor(() => {
      expect(supabaseFromMock).toHaveBeenCalledWith("tasks");
      expect(insertTaskMock).toHaveBeenCalledTimes(2);
      expect(insertTaskMock).toHaveBeenCalledWith(
        expect.objectContaining({
          tablo_id: "tablo-1",
          title: "Task from etape",
          status: "todo",
          assignee_id: null,
          position: 0,
          parent_task_id: "etape-1",
          is_parent: false,
          description: null,
          due_date: null,
        })
      );
      expect(updateTaskMock).toHaveBeenCalledWith({ title: "Updated task title" });
      expect(updateTaskMock).toHaveBeenCalledWith({ position: 7, status: "done" });
      expect(updateTaskMock).toHaveBeenCalledWith({ status: "done" });
      expect(deleteTaskMock).toHaveBeenCalledTimes(1);
    });
  });

  it("renders the main-route style header metadata and discussion CTA", () => {
    renderWithProviders(<ClientTabloPage />, {
      route: "/tablo/tablo-1",
      path: "/tablo/:tabloId",
    });

    expect(screen.getByText("Client Project")).toBeInTheDocument();
    expect(screen.getAllByRole("button", { name: "Discussion" })).toHaveLength(2);
    expect(screen.getAllByText("Rôle").length).toBeGreaterThan(0);
    expect(screen.getAllByText("Créé le").length).toBeGreaterThan(0);
    expect(screen.getAllByText("Progression").length).toBeGreaterThan(0);
  });

  it("keeps the shared main-app header labels even when the client locale is english", () => {
    renderWithProviders(<ClientTabloPage />, {
      route: "/tablo/tablo-1",
      path: "/tablo/:tabloId",
      language: "en",
    });

    expect(screen.getAllByText("Rôle").length).toBeGreaterThan(0);
    expect(screen.getAllByText("Créé le").length).toBeGreaterThan(0);
    expect(screen.getAllByText("Progression").length).toBeGreaterThan(0);
    expect(screen.queryByText("Role")).not.toBeInTheDocument();
    expect(screen.queryByText("Created on")).not.toBeInTheDocument();
    expect(screen.queryByText("Progress")).not.toBeInTheDocument();
  });

  it("keeps client restrictions by hiding invite and layout-edit controls", () => {
    renderWithProviders(<ClientTabloPage />, {
      route: "/tablo/tablo-1",
      path: "/tablo/:tabloId",
    });

    expect(screen.queryByRole("button", { name: "Inviter" })).not.toBeInTheDocument();
    expect(
      screen.queryByRole("button", { name: "Modifier la mise en page" })
    ).not.toBeInTheDocument();
  });

  it("renders a read-only overview matching the main route cards", () => {
    renderWithProviders(<ClientTabloPage />, {
      route: "/tablo/tablo-1",
      path: "/tablo/:tabloId",
    });

    expect(screen.getByText("Description du projet")).toBeInTheDocument();
    expect(screen.getByText("Mes tâches")).toBeInTheDocument();
    expect(screen.getByText("Informations")).toBeInTheDocument();
    expect(screen.queryByRole("button", { name: "Ajouter" })).not.toBeInTheDocument();
  });

  it("lets the client quickly toggle a task from the overview card", async () => {
    const { user } = renderWithProviders(<ClientTabloPage />, {
      route: "/tablo/tablo-1",
      path: "/tablo/:tabloId",
    });

    await user.click(screen.getByRole("button", { name: "Prepare proposal" }));

    await waitFor(() => {
      expect(updateTaskMock).toHaveBeenCalledWith({ status: "done" });
    });
  });

  it("wires file and folder actions in the client files tab while keeping file deletion disabled", async () => {
    const { user } = renderWithProviders(<ClientTabloPage />, {
      route: "/tablo/tablo-1",
      path: "/tablo/:tabloId",
    });

    await user.click(screen.getByRole("button", { name: "Fichiers" }));

    expect(latestTabloFilesSectionProps?.isReadOnly).toBe(false);
    expect(latestTabloFilesSectionProps?.onCreateFile).toBeTypeOf("function");
    expect(latestTabloFilesSectionProps?.onDownloadFile).toBeTypeOf("function");
    expect(latestTabloFilesSectionProps?.onCreateFolder).toBeTypeOf("function");
    expect(latestTabloFilesSectionProps?.onUpdateFolder).toBeTypeOf("function");
    expect(latestTabloFilesSectionProps?.onDeleteFolder).toBeTypeOf("function");
    expect(latestTabloFilesSectionProps?.onDeleteFile).toBeUndefined();

    await user.click(screen.getByRole("button", { name: "Créer fichier test" }));
    await user.click(screen.getByRole("button", { name: "Télécharger fichier test" }));
    await user.click(screen.getByRole("button", { name: "Créer livrable test" }));
    await user.click(screen.getByRole("button", { name: "Modifier livrable test" }));
    await user.click(screen.getByRole("button", { name: "Supprimer livrable test" }));

    await waitFor(() => {
      expect(apiPostMock).toHaveBeenCalledWith("/api/v1/tablo-data/tablo-1/file/brief.pdf", {
        content: "data:application/pdf;base64,AAAA",
        contentType: "application/pdf",
      });
      expect(apiGetMock).toHaveBeenCalledWith("/api/v1/tablo-data/tablo-1/brief.pdf");
      expect(apiPostMock).toHaveBeenCalledWith("/api/v1/tablo-data/tablo-1/folders", {
        name: "Livrable",
        description: "Desc",
      });
      expect(apiPutMock).toHaveBeenCalledWith("/api/v1/tablo-data/tablo-1/folders/folder-1", {
        name: "Livrable mis à jour",
        description: "Desc",
      });
      expect(apiDeleteMock).toHaveBeenCalledWith("/api/v1/tablo-data/tablo-1/folders/folder-1");
    });
  });
});
