import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import {
  cleanup,
  fireEvent,
  render,
  screen,
  waitFor,
} from "@testing-library/react";
import type React from "react";
import { MemoryRouter, Route, Routes } from "react-router-dom";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { createI18nMock } from "../../test/i18nMock";
import * as adminApi from "../../lib/adminApi";
import { TenantWorksmobilePage } from "../tenants/routes/TenantWorksmobilePage";
import TenantListPage from "../tenants/routes/TenantListPage";
import UserCreatePage from "../users/UserCreatePage";
import UserDetailPage from "../users/UserDetailPage";

const tenantItems = [
  {
    id: "tenant-root",
    type: "COMPANY_GROUP",
    name: "한맥 가족",
    slug: "hanmac-family",
    description: "root",
    status: "active",
    memberCount: 0,
    createdAt: "2026-05-01T00:00:00Z",
    updatedAt: "2026-05-01T00:00:00Z",
  },
  {
    id: "tenant-company",
    type: "COMPANY",
    parentId: "tenant-root",
    name: "GPDTDC",
    slug: "gpdtdc",
    description: "company",
    status: "active",
    memberCount: 2,
    config: {
      userSchema: [
        {
          key: "employee_id",
          label: "사번",
          type: "text",
          required: false,
        },
      ],
    },
    createdAt: "2026-05-01T00:00:00Z",
    updatedAt: "2026-05-01T00:00:00Z",
  },
  {
    id: "tenant-leaf",
    type: "ORGANIZATION",
    parentId: "tenant-company",
    name: "기술연구팀",
    slug: "gpdtdc-rnd",
    description: "leaf",
    status: "active",
    memberCount: 1,
    createdAt: "2026-05-01T00:00:00Z",
    updatedAt: "2026-05-01T00:00:00Z",
  },
];

const userDetail = {
  id: "user-1",
  email: "engineer@example.com",
  name: "Engineer User",
  phone: "010-0000-0000",
  role: "user",
  status: "active",
  tenantSlug: "gpdtdc-rnd",
  tenantId: "tenant-leaf",
  department: "기술연구팀",
  grade: "책임",
  position: "팀장",
  jobTitle: "Backend",
  metadata: {
    employee_id: "EMP001",
    sub_email: ["engineer.sub@example.com"],
  },
  tenant: tenantItems[2],
  appointments: [
    {
      tenantId: "tenant-leaf",
      tenantSlug: "gpdtdc-rnd",
      tenantName: "기술연구팀",
      isPrimary: true,
      isOwner: false,
      isAdmin: false,
      isManager: true,
      department: "기술연구팀",
      grade: "책임",
      position: "팀장",
      jobTitle: "Backend",
      metadata: { employee_id: "EMP001" },
    },
  ],
  createdAt: "2026-05-01T00:00:00Z",
  updatedAt: "2026-05-02T00:00:00Z",
};

vi.mock("../../lib/i18n", () => createI18nMock());

vi.mock("../../components/auth/RoleGuard", () => ({
  RoleGuard: ({ children }: { children: React.ReactNode }) => <>{children}</>,
}));

vi.mock("../../lib/adminApi", () => ({
  fetchMe: vi.fn(async () => ({
    id: "admin-1",
    role: "super_admin",
    name: "Admin User",
    email: "admin@example.com",
  })),
  fetchAllTenants: vi.fn(async () => ({
    items: tenantItems,
    total: tenantItems.length,
  })),
  fetchTenants: vi.fn(async () => ({
    items: tenantItems,
    limit: 500,
    offset: 0,
    total: tenantItems.length,
    nextCursor: null,
  })),
  fetchTenant: vi.fn(async (id: string) => {
    return tenantItems.find((tenant) => tenant.id === id) ?? tenantItems[1];
  }),
  createUser: vi.fn(async () => ({
    id: "created-user",
    email: "created@example.com",
    generatedPassword: "GeneratedPassword!1",
  })),
  fetchUser: vi.fn(async () => userDetail),
  fetchUserRpHistory: vi.fn(async () => [
    {
      client_id: "orgfront",
      client_name: "OrgFront",
      last_login_at: "2026-05-01T00:00:00Z",
      login_count: 3,
    },
  ]),
  fetchPasswordPolicy: vi.fn(async () => ({
    minLength: 12,
    lowercase: true,
    uppercase: true,
    number: true,
    nonAlphanumeric: true,
    minCharacterTypes: 3,
  })),
  updateUser: vi.fn(async () => userDetail),
  deleteUser: vi.fn(async () => undefined),
  updateTenant: vi.fn(async () => tenantItems[1]),
  deleteTenantsBulk: vi.fn(async () => ({ deleted: 1 })),
  exportTenantsCSV: vi.fn(async () => new Blob(["name,slug\nGPDTDC,gpdtdc"])),
  importTenantsCSV: vi.fn(async () => ({
    created: 1,
    updated: 0,
    failed: 0,
    errors: [],
  })),
  fetchWorksmobileOverview: vi.fn(async () => ({
    tenant: tenantItems[1],
    config: {
      enabled: true,
      tokenConfigured: true,
      adminTenantId: "works-admin",
      domainMappings: { "example.com": 1001 },
    },
    recentJobs: [
      {
        id: "job-1",
        resourceType: "USER",
        resourceId: "user-1",
        action: "SYNC",
        status: "failed",
        retryCount: 1,
        lastError: "temporary failure",
        createdAt: "2026-05-01T00:00:00Z",
        updatedAt: "2026-05-01T00:10:00Z",
      },
    ],
  })),
  fetchWorksmobileComparison: vi.fn(async () => ({
    users: [
      {
        resourceType: "USER",
        baronId: "user-1",
        baronName: "Engineer User",
        baronEmail: "engineer@example.com",
        baronPrimaryOrgId: "tenant-leaf",
        baronPrimaryOrgName: "기술연구팀",
        worksmobileId: "works-user-1",
        worksmobileName: "Engineer User",
        worksmobileEmail: "engineer@example.com",
        worksmobilePrimaryOrgId: "works-org-1",
        worksmobilePrimaryOrgName: "기술연구팀",
        status: "matched",
      },
      {
        resourceType: "USER",
        baronId: "user-2",
        baronName: "New User",
        baronEmail: "new@example.com",
        worksmobileJobStatus: "failed",
        worksmobileJobRetryCount: 2,
        worksmobileLastError: "worksmobile api failed",
        status: "missing_in_worksmobile",
      },
      {
        resourceType: "USER",
        baronId: "user-3",
        baronName: "Next User",
        baronEmail: "next@example.com",
        status: "missing_in_worksmobile",
      },
    ],
    groups: [
      {
        resourceType: "ORG_UNIT",
        baronId: "tenant-leaf",
        baronSlug: "gpdtdc-rnd",
        baronName: "기술연구팀",
        worksmobileId: "works-org-1",
        worksmobileName: "기술연구팀",
        status: "needs_update",
      },
    ],
  })),
  fetchWorksmobileCredentialBatches: vi.fn(async () => [
    {
      batchId: "credential-batch-1",
      operation: "worksmobile_user_sync",
      userCount: 1,
      processedCount: 1,
      failedCount: 1,
      hasPasswords: true,
      failures: [
        {
          userId: "failed-user",
          email: "failed-user@samaneng.com",
          status: "failed",
          retryCount: 2,
          lastError: "worksmobile api failed",
          updatedAt: "2026-06-01T04:05:00Z",
        },
      ],
      createdAt: "2026-06-01T04:00:00Z",
      updatedAt: "2026-06-01T04:00:00Z",
    },
    {
      batchId: "credential-batch-pending",
      operation: "worksmobile_user_sync",
      userCount: 2,
      pendingCount: 1,
      processingCount: 1,
      processedCount: 0,
      failedCount: 0,
      hasPasswords: true,
      createdAt: "2026-06-01T04:10:00Z",
      updatedAt: "2026-06-01T04:10:00Z",
    },
  ]),
  enqueueWorksmobileBackfillDryRun: vi.fn(async () => ({ id: "job-dry" })),
  retryWorksmobileJob: vi.fn(async () => ({ id: "job-retry" })),
  downloadWorksmobileInitialPasswordsCSV: vi.fn(async () => ({
    blob: new Blob(["id"]),
    filename: "worksmobile_initial_passwords.csv",
  })),
  enqueueWorksmobileOrgUnitSync: vi.fn(async () => ({ id: "job-org" })),
  enqueueWorksmobileOrgUnitDelete: vi.fn(async () => ({ id: "job-delete" })),
  enqueueWorksmobileUserSync: vi.fn(async () => ({ id: "job-user" })),
  resetWorksmobileUserPassword: vi.fn(async () => ({ id: "job-reset" })),
  deleteWorksmobileCredentialBatchPasswords: vi.fn(async () => ({
    batchId: "credential-batch-1",
    userCount: 1,
    hasPasswords: false,
  })),
}));

function renderWithProviders(ui: React.ReactElement, entry = "/") {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: { retry: false },
      mutations: { retry: false },
    },
  });

  return render(
    <QueryClientProvider client={queryClient}>
      <MemoryRouter initialEntries={[entry]}>{ui}</MemoryRouter>
    </QueryClientProvider>,
  );
}

describe("adminfront large page coverage smoke", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    if (typeof window !== "undefined") {
      (window as any)._IS_TEST_MODE = true;
    }
  });

  it("renders user creation form with tenant context", async () => {
    renderWithProviders(
      <Routes>
        <Route path="/users/new" element={<UserCreatePage />} />
      </Routes>,
      "/users/new?tenantSlug=gpdtdc-rnd",
    );

    expect(await screen.findByText("사용자 추가")).toBeInTheDocument();
    expect(screen.getByLabelText("이메일")).toBeInTheDocument();
  });

  it("renders user detail form and RP history", async () => {
    renderWithProviders(
      <Routes>
        <Route path="/users/:id" element={<UserDetailPage />} />
      </Routes>,
      "/users/user-1",
    );

    expect(await screen.findByDisplayValue("Engineer User")).toBeInTheDocument();
    expect(screen.getAllByText("기술연구팀").length).toBeGreaterThan(0);
    expect(screen.getByDisplayValue("engineer@example.com")).toBeInTheDocument();
  });

  it("renders tenant list hierarchy", async () => {
    renderWithProviders(
      <Routes>
        <Route path="/tenants" element={<TenantListPage />} />
      </Routes>,
      "/tenants",
    );

    expect(await screen.findByText("GPDTDC")).toBeInTheDocument();
    expect(screen.getByText("기술연구팀")).toBeInTheDocument();
  });

  it("renders worksmobile comparison screens", async () => {
    cleanup();
    renderWithProviders(
      <Routes>
        <Route
          path="/tenants/:tenantId/worksmobile"
          element={<TenantWorksmobilePage />}
        />
      </Routes>,
      "/tenants/tenant-company/worksmobile",
    );

    expect(await screen.findByText("Worksmobile 연동")).toBeInTheDocument();
    expect(await screen.findByText("Baron / Works 비교")).toBeInTheDocument();
    expect(
      await screen.findByText("최근 실패: worksmobile api failed"),
    ).toBeInTheDocument();
    expect(screen.getByText("Backfill Dry-run")).toBeInTheDocument();
    expect(screen.queryByRole("button", { name: "초기 비밀번호 CSV" })).toBeNull();
  });

  it("does not automatically download the selected Worksmobile user credential batch after create enqueue", async () => {
    vi.spyOn(window.URL, "createObjectURL").mockReturnValue("blob:test");
    vi.spyOn(window.URL, "revokeObjectURL").mockImplementation(() => {});
    renderWithProviders(
      <Routes>
        <Route
          path="/tenants/:tenantId/worksmobile"
          element={<TenantWorksmobilePage />}
        />
      </Routes>,
      "/tenants/tenant-company/worksmobile",
    );

    await screen.findByText("New User");
    fireEvent.click(screen.getByRole("checkbox", { name: "New User 선택" }));
    fireEvent.click(
      screen.getByRole("button", { name: "선택 구성원 WORKS에 생성" }),
    );

    await waitFor(() =>
      expect(adminApi.enqueueWorksmobileUserSync).toHaveBeenCalledWith(
        "tenant-company",
        "user-2",
        expect.any(String),
      ),
    );
    const credentialBatchId = vi.mocked(
      adminApi.enqueueWorksmobileUserSync,
    ).mock.calls[0][2];
    expect(adminApi.downloadWorksmobileInitialPasswordsCSV).not.toHaveBeenCalled();
  });

  it("continues selected Worksmobile user create enqueue after one row fails", async () => {
    vi.mocked(adminApi.enqueueWorksmobileUserSync)
      .mockRejectedValueOnce(new Error("sync failed"))
      .mockResolvedValueOnce({ id: "job-user-3" } as never);
    vi.spyOn(window.URL, "createObjectURL").mockReturnValue("blob:test");
    vi.spyOn(window.URL, "revokeObjectURL").mockImplementation(() => {});
    renderWithProviders(
      <Routes>
        <Route
          path="/tenants/:tenantId/worksmobile"
          element={<TenantWorksmobilePage />}
        />
      </Routes>,
      "/tenants/tenant-company/worksmobile",
    );

    await screen.findByText("New User");
    fireEvent.click(screen.getByRole("checkbox", { name: "New User 선택" }));
    fireEvent.click(screen.getByRole("checkbox", { name: "Next User 선택" }));
    fireEvent.click(
      screen.getByRole("button", { name: "선택 구성원 WORKS에 생성" }),
    );

    await waitFor(() =>
      expect(adminApi.enqueueWorksmobileUserSync).toHaveBeenCalledTimes(2),
    );
    expect(adminApi.enqueueWorksmobileUserSync).toHaveBeenNthCalledWith(
      1,
      "tenant-company",
      "user-2",
      expect.any(String),
    );
    expect(adminApi.enqueueWorksmobileUserSync).toHaveBeenNthCalledWith(
      2,
      "tenant-company",
      "user-3",
      expect.any(String),
    );
    expect(adminApi.downloadWorksmobileInitialPasswordsCSV).not.toHaveBeenCalled();
  });

  it("downloads or deletes Worksmobile credential batches from history", async () => {
    vi.spyOn(window.URL, "createObjectURL").mockReturnValue("blob:test");
    vi.spyOn(window.URL, "revokeObjectURL").mockImplementation(() => {});
    vi.spyOn(window, "confirm").mockReturnValue(true);
    renderWithProviders(
      <Routes>
        <Route
          path="/tenants/:tenantId/worksmobile"
          element={<TenantWorksmobilePage />}
        />
      </Routes>,
      "/tenants/tenant-company/worksmobile",
    );

    fireEvent.click(screen.getByRole("tab", { name: "이력" }));
    await screen.findByText("credential-batch-1");
    expect(
      screen.getByRole("button", {
        name: "credential-batch-pending 비밀번호 CSV 다운로드",
      }),
    ).toBeDisabled();
    fireEvent.click(
      screen.getByRole("button", {
        name: "credential-batch-1 비밀번호 CSV 다운로드",
      }),
    );
    await waitFor(() =>
      expect(
        adminApi.downloadWorksmobileInitialPasswordsCSV,
      ).toHaveBeenCalledWith("tenant-company", "credential-batch-1"),
    );

    fireEvent.click(
      screen.getByRole("button", {
        name: "credential-batch-1 비밀번호 값 삭제",
      }),
    );
    await waitFor(() =>
      expect(
        adminApi.deleteWorksmobileCredentialBatchPasswords,
      ).toHaveBeenCalledWith("tenant-company", "credential-batch-1"),
    );

    fireEvent.click(
      screen.getByRole("button", {
        name: "credential-batch-1 실패 사유 보기",
      }),
    );
    expect(await screen.findByText("failed-user@samaneng.com")).toBeInTheDocument();
    expect(screen.getByText("worksmobile api failed")).toBeInTheDocument();
  });

  it("enqueues Worksmobile password reset as a credential batch", async () => {
    vi.spyOn(window, "confirm").mockReturnValue(true);
    renderWithProviders(
      <Routes>
        <Route
          path="/tenants/:tenantId/worksmobile"
          element={<TenantWorksmobilePage />}
        />
      </Routes>,
      "/tenants/tenant-company/worksmobile",
    );

    await screen.findByText("Worksmobile 연동");
    fireEvent.click(screen.getAllByRole("button", { name: "양쪽 다 있음" })[0]);
    await screen.findAllByText("Engineer User");
    fireEvent.click(
      screen.getByRole("button", {
        name: "Engineer User 비밀번호 재설정",
      }),
    );

    await waitFor(() =>
      expect(adminApi.resetWorksmobileUserPassword).toHaveBeenCalledWith(
        "tenant-company",
        "user-1",
        expect.any(String),
      ),
    );
    expect(adminApi.downloadWorksmobileInitialPasswordsCSV).not.toHaveBeenCalled();
  });
});
