/// <reference types="cypress" />

const AUTH_COOKIE_KEYS = {
  accessToken: "TENDER_PANEL_token",
  refreshToken: "TENDER_PANEL_refresh_token",
  user: "TENDER_PANEL_user",
} as const;

const createAdminUser = (overrides: Partial<Record<string, any>> = {}) => ({
  id: "507f1f77bcf86cd799439012",
  full_name: "E2E Admin One",
  username: "e2e-admin-one",
  email: "e2e-admin-one@example.com",
  role: "admin",
  status: "active",
  ...overrides,
});

Cypress.Commands.add("loginAsAdmin", () => {
  cy.session(
    "admin-session",
    () => {
      cy.visit("/auth/sign-in");

      cy.setCookie(AUTH_COOKIE_KEYS.accessToken, "e2e-access-token");
      cy.setCookie(AUTH_COOKIE_KEYS.refreshToken, "e2e-refresh-token");
      cy.setCookie(
        AUTH_COOKIE_KEYS.user,
        encodeURIComponent(
          JSON.stringify({
            id: "507f1f77bcf86cd799439012",
            username: "e2e-admin",
            email: "e2e-admin@example.com",
            role: "admin",
          }),
        ),
      );
    },
    {
      validate: () => {
        cy.getCookie(AUTH_COOKIE_KEYS.accessToken).should("exist");
        cy.getCookie(AUTH_COOKIE_KEYS.user).should("exist");
      },
      cacheAcrossSpecs: true,
    },
  );
});

Cypress.Commands.add("getByCy", (value: string) => cy.get(`[data-cy="${value}"]`));

Cypress.Commands.add("setAuthCookies", (userOverrides = {}) => {
  cy.setCookie(AUTH_COOKIE_KEYS.accessToken, "e2e-access-token");
  cy.setCookie(AUTH_COOKIE_KEYS.refreshToken, "e2e-refresh-token");
  cy.setCookie(
    AUTH_COOKIE_KEYS.user,
    encodeURIComponent(
      JSON.stringify(
        createAdminUser({
          id: "507f1f77bcf86cd799439011",
          ...userOverrides,
        }),
      ),
    ),
  );
});

Cypress.Commands.add("mockAdminsList", (options: Cypress.AdminListMockOptions = {}) => {
  const users = options.users ?? [createAdminUser()];
  const offset = options.offset ?? 0;
  const limit = options.limit ?? 10;
  const total = options.total ?? users.length;
  const statusCode = options.statusCode ?? 200;
  const delay = options.delay ?? 0;
  const query = options.query
    ? Object.fromEntries(
        Object.entries(options.query).map(([key, value]) => [key, String(value)]),
      )
    : undefined;

  cy.intercept(
    {
      method: "GET",
      url: "**/api/proxy/users**",
      query,
    },
    (req) => {
      req.reply({
        delay,
        statusCode,
        body: {
          success: statusCode < 400,
          message: statusCode < 400 ? "ok" : "failed",
          data: { users },
          meta: { offset, limit, total },
        },
      });
    },
  ).as(options.alias ?? "getAdmins");
});

Cypress.Commands.add("mockCreateAdmin", (options = {}) => {
  const statusCode = options.statusCode ?? 201;
  cy.intercept("POST", "**/api/proxy/users", {
    statusCode,
    body: options.body ?? {
      success: statusCode < 400,
      message: options.message ?? "Admin created successfully",
      data: {},
    },
    delay: options.delay ?? 0,
  }).as(options.alias ?? "createAdmin");
});

Cypress.Commands.add("mockUpdateAdmin", (id: string, options = {}) => {
  const statusCode = options.statusCode ?? 200;
  cy.intercept("PUT", `**/api/proxy/users/${id}`, {
    statusCode,
    body: options.body ?? {
      success: statusCode < 400,
      message: options.message ?? "Admin updated successfully",
      data: {},
    },
    delay: options.delay ?? 0,
  }).as(options.alias ?? "updateAdmin");
});

Cypress.Commands.add("mockDeleteAdmin", (id: string, options = {}) => {
  const statusCode = options.statusCode ?? 200;
  cy.intercept("DELETE", `**/api/proxy/users/${id}`, {
    statusCode,
    body: options.body ?? {
      success: statusCode < 400,
      message: options.message ?? "Admin deleted successfully",
      data: {},
    },
    delay: options.delay ?? 0,
  }).as(options.alias ?? "deleteAdmin");
});

Cypress.Commands.add("mockChangeAdminStatus", (id: string, options = {}) => {
  const statusCode = options.statusCode ?? 200;
  cy.intercept("PUT", `**/api/proxy/users/${id}/status`, {
    statusCode,
    body: options.body ?? {
      success: statusCode < 400,
      message: options.message ?? "Status changed successfully",
      data: {},
    },
    delay: options.delay ?? 0,
  }).as(options.alias ?? "changeAdminStatus");
});
