/**
 * Full customer onboarding journey, both apps:
 *
 *   1. portal    — /signup form → OTP (read from DB, delivery is off in e2e)
 *                  → account created → onboarding wizard (nationality/role →
 *                  company → personnel → contact → PoA → documents incl. the
 *                  per-role business license) → "Submit for review"
 *   2. backoffice — staff (chief, holds edr_freight_app:admin) approves the
 *                  importer profile on /dashboard/customers/:id
 *   3. portal    — the new customer is active: contract wizard reachable
 *
 * Tests are sequential steps of ONE journey (fresh unique user per run), so
 * retries are disabled — a mid-journey retry would replay a non-idempotent
 * step against already-advanced state.
 *
 * NOTE: switching origin between tests (portal 5373 ↔ backoffice 5383)
 * reloads the spec bundle and resets module state — later tests resolve the
 * journey's user/company from the DB instead of module variables.
 */

const stamp = Date.now();
const email = `e2e.onboard.${stamp}@example.com`;
// Ethiopian mobile: 9 + 8 digits, unique per run.
const phoneNational = `9${String(stamp).slice(-8)}`;
const signupPassword = "Password@e2e1";
const companyName = `E2E Onboard Co ${stamp}`;
const tin = String(stamp).slice(-10).padStart(10, "1");
const vat = String(stamp + 1).slice(-10).padStart(10, "2");
const fan = String(stamp).slice(-13).padStart(16, "3");

const portal = () => Cypress.env("portalUrl") as string;

/** The journey's company/user = the latest e2e.onboard.* signup in the DB. */
function latestOnboardJourney() {
  return cy.task<{ rows: Array<{ name: string; email: string }> }>("db:query", {
    sql: `SELECT c.name, u.email
          FROM freight.companies c
          JOIN freight.external_profiles ep ON ep.company_id = c.id
          JOIN iam.users u ON u.id = ep.user_id
          WHERE u.email LIKE 'e2e.onboard.%'
          ORDER BY c.created_at DESC LIMIT 1`,
  });
}

/** Fill a labelled Mantine input (label[for] → input id). */
function fill(label: string | RegExp, value: string) {
  cy.contains("label", label)
    .invoke("attr", "for")
    .then((id) => {
      cy.get(`[id="${id}"]`).clear({ force: true }).type(value, { force: true });
    });
}

/** The wizard's phone inputs (react-phone-number-input, type=tel). */
function fillPhone(index: number, national: string) {
  cy.get('.mantine-Modal-content input[type="tel"]')
    .eq(index)
    .clear({ force: true })
    .type(national, { force: true });
}

describe("customer onboarding journey", { retries: 0 }, () => {
  it("signs up with OTP and completes the onboarding wizard", () => {
    // The eTrade TIN lookup 400s in e2e (external service unreachable). The
    // form handles it ("fill in the details manually") but axios also throws
    // an uncaught rejection — ignore just that one.
    cy.on("uncaught:exception", (err) =>
      err.message.includes("Request failed with status code 400") ? false : true,
    );
    cy.visit(`${portal()}/signup`);

    fill(/^First name/, "Onboard");
    fill(/^Last name/, "Tester");
    fill(/^Email/, email);
    cy.get('input[type="tel"]').first().type(phoneNational, { force: true });
    fill(/^Password/, signupPassword);
    fill(/^Confirm password/, signupPassword);
    cy.contains("button", "Continue").click();

    // OTP stage — the code is generated + stored even though delivery is off.
    cy.contains("Verify", { timeout: 15000 }).should("be.visible");
    cy.getOtp(email).then((otp) => cy.typeOtp(otp));
    cy.contains("button", "Verify & create account").click();

    // Signed in → /portal → wizard auto-opens on the nationality/role step.
    cy.location("pathname", { timeout: 20000 }).should("eq", "/portal");
    cy.contains("Where is your company registered?", { timeout: 15000 }).should(
      "be.visible",
    );
    cy.contains("button", "Ethiopian Company").click();
    cy.contains("button", "Importer").click();
    cy.get(".mantine-Modal-content").contains("button", "Continue").click();

    // Company step. TIN first — the eTrade auto-lookup fails in e2e (no
    // external network) and the form allows manual entry.
    cy.get('input[placeholder="0012345678"]', { timeout: 15000 }).type(tin);
    fill(/^Company Name/, companyName);
    fill(/^Company Email/, `ops.${stamp}@example.com`);
    fillPhone(0, "911234567");
    fill(/^Location/, "Addis Ababa, Ethiopia");
    fill(/^VAT Number/, vat);
    cy.get('input[placeholder="1234567890123456"]').type(fan);
    cy.mantineSelect(/^Region/, "Addis Ababa");
    fill(/^Zone/, "Zone 1");
    fill(/^Woreda/, "Woreda 1");
    fill(/^Kebele/, "Kebele 1");
    fill(/^House No/, "123");
    cy.get(".mantine-Modal-content").contains("button", "Continue").click();

    // Personnel (general manager).
    fill(/^Name/, "General Manager");
    fill(/^Email/, `gm.${stamp}@example.com`);
    fillPhone(0, "911234568");
    cy.get(".mantine-Modal-content").contains("button", "Continue").click();

    // Contact person.
    fill(/^Name/, "Contact Person");
    fillPhone(0, "911234569");
    cy.get(".mantine-Modal-content").contains("button", "Continue").click();

    // PoA — optional for an importer.
    cy.get(".mantine-Modal-content").contains("button", "Continue").click();

    // Documents: no company docs are configured in e2e, but every role needs
    // a business license.
    cy.contains("Business license", { timeout: 15000 }).should("be.visible");
    cy.get('.mantine-Modal-content input[type="file"]')
      .first()
      .selectFile("cypress/fixtures/docs/license.pdf", { force: true });
    cy.get(".mantine-Modal-content")
      .contains("button", "Submit for review")
      .click();

    cy.contains("You're all set", { timeout: 30000 }).should("be.visible");

    // DB cross-check: submitted, awaiting approval.
    cy.task<{ rows: Array<{ status: string; onboarding_completed: boolean }> }>(
      "db:query",
      {
        sql: `SELECT c.status, ep.onboarding_completed
              FROM freight.companies c
              JOIN freight.external_profiles ep ON ep.company_id = c.id
              JOIN iam.users u ON u.id = ep.user_id
              WHERE u.email = $1`,
        params: [email],
      },
    ).then(({ rows }) => {
      expect(rows, "company row").to.have.length(1);
      expect(rows[0].status).to.eq("pending");
      expect(rows[0].onboarding_completed).to.eq(true);
    });
  });

  it("backoffice staff approves the submitted importer profile", () => {
    cy.loginBackoffice("chief@edr.local");
    cy.visit("/dashboard/customers");

    latestOnboardJourney().then(({ rows }) => {
      expect(rows, "onboarded company").to.have.length(1);
      const company = rows[0].name;

      cy.get('input[placeholder*="Search by company"]').type(company);
      cy.contains(company, { timeout: 15000 }).click();

      // Role profiles table → approve the pending importer profile. Once
      // active, the row's action flips to "Suspend".
      cy.contains("button", "Approve", { timeout: 15000 }).click();
      cy.contains("button", "Suspend", { timeout: 15000 }).should("be.visible");

      cy.task<{ rows: Array<{ status: string; reference: string | null; company_status: string }> }>(
        "db:query",
        {
          sql: `SELECT p.status, p.reference, c.status AS company_status
                FROM freight.company_profiles p
                JOIN freight.companies c ON c.id = p.company_id
                WHERE c.name = $1 AND p.type = 'importer'`,
          params: [company],
        },
      ).then(({ rows: profiles }) => {
        expect(profiles, "importer profile").to.have.length(1);
        expect(profiles[0].status).to.eq("active");
        expect(profiles[0].reference, "minted reference").to.be.a("string").and
          .not.be.empty;
        expect(profiles[0].company_status).to.eq("active");
      });
    });
  });

  it("the approved customer can reach the contract wizard", () => {
    latestOnboardJourney().then(({ rows }) => {
      cy.loginPortal(rows[0].email, signupPassword);
    });
    cy.visitPortal("/contracts/new");

    // No "Awaiting Approval" gate — the wizard's first step renders.
    cy.contains("label", "Operation Type", { timeout: 15000 }).should(
      "be.visible",
    );
    cy.contains("Awaiting Approval").should("not.exist");
  });
});

export {};
