/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

import { render } from "@testing-library/react";
import {
  StockTicker,
  getDirection,
  formatPrice,
  formatChange,
} from "content-src/components/Widgets/Stocks/StockTicker";

describe("getDirection", () => {
  it("returns up/down/flat from the change sign", () => {
    expect(getDirection("+2.1")).toBe("up");
    expect(getDirection("-0.11")).toBe("down");
    expect(getDirection("0.00")).toBe("flat");
    expect(getDirection(undefined)).toBe("flat");
  });
});

describe("formatPrice", () => {
  it("formats the parsed price as US currency for an en-US locale", () => {
    expect(formatPrice("$559.44 USD", "en-US")).toBe("$559.44");
  });

  it("keeps thousands separators", () => {
    expect(formatPrice("$1,234.56 USD", "en-US")).toBe("$1,234.56");
  });

  it("uses the locale's decimal separator and symbol placement", () => {
    // French uses a comma decimal separator and places the symbol after the amount.
    const fr = formatPrice("$559.44 USD", "fr-FR");
    expect(fr).toContain("559,44");
    expect(fr).not.toContain("559.44");
  });

  it("returns the raw string when there is no number to parse", () => {
    expect(formatPrice("", "en-US")).toBe("");
    expect(formatPrice(undefined, "en-US")).toBe("");
  });
});

describe("formatChange", () => {
  it("formats the change as a signed percent for an en-US locale", () => {
    expect(formatChange("+0.2", "en-US")).toBe("+0.2%");
    expect(formatChange("-0.21", "en-US")).toBe("-0.21%");
  });

  it("shows no sign for a flat change and keeps the source precision", () => {
    expect(formatChange("0.00", "en-US")).toBe("0.00%");
  });

  it("formats an integer change with no decimal places", () => {
    expect(formatChange("+1", "en-US")).toBe("+1%");
  });

  it("uses the locale's decimal separator", () => {
    const fr = formatChange("+0.2", "fr-FR");
    expect(fr).toContain("0,2");
    expect(fr).not.toContain("0.2");
  });

  it("returns the raw string when there is no number to parse", () => {
    expect(formatChange("", "en-US")).toBe("");
  });
});

describe("StockTicker", () => {
  function renderCard(props = {}) {
    const { container } = render(
      <StockTicker
        name="SPDR S&P 500 ETF Trust"
        ticker="SPY"
        price="$559.44 USD"
        changePercent="+2.1"
        {...props}
      />
    );
    return container;
  }

  it("renders ticker, formatted price and formatted change as visual (aria-hidden) text", () => {
    const container = renderCard();
    expect(container.querySelector(".stock-ticker-symbol").textContent).toBe(
      "SPY"
    );
    expect(container.querySelector(".stock-ticker-price").textContent).toBe(
      "$559.44"
    );
    expect(container.querySelector(".stock-ticker-change").textContent).toBe(
      "+2.1%"
    );
  });

  it("applies the direction modifier to the indicator and change", () => {
    const up = renderCard();
    expect(up.querySelector(".stock-indicator--up")).toBeTruthy();
    expect(up.querySelector(".stock-ticker-change--up")).toBeTruthy();

    const down = render(
      <StockTicker name="n" ticker="IWM" price="$1 USD" changePercent="-0.21" />
    ).container;
    expect(down.querySelector(".stock-indicator--down")).toBeTruthy();
    expect(down.querySelector(".stock-ticker-change--down")).toBeTruthy();
  });

  it("falls through to the base color when the change is flat", () => {
    const flat = render(
      <StockTicker name="n" ticker="IWM" price="$1 USD" changePercent="0.00" />
    ).container;
    expect(flat.querySelector(".stock-indicator--flat")).toBeTruthy();
    expect(flat.querySelector(".stock-ticker-change--up")).toBeNull();
    expect(flat.querySelector(".stock-ticker-change--down")).toBeNull();
  });

  it("sets the flat arrow inline and mirrors it for right-to-left locales", () => {
    const ltr = render(
      <StockTicker name="n" ticker="DIA" price="$1 USD" changePercent="0.00" />
    ).container;
    expect(
      ltr.querySelector(".stock-indicator--flat").style.backgroundImage
    ).toContain("shaft-arrow-right.svg");

    document.dir = "rtl";
    try {
      const rtl = render(
        <StockTicker
          name="n"
          ticker="DIA"
          price="$1 USD"
          changePercent="0.00"
        />
      ).container;
      expect(
        rtl.querySelector(".stock-indicator--flat").style.backgroundImage
      ).toContain("shaft-arrow-left.svg");
    } finally {
      document.dir = "";
    }
  });

  it("marks the visual rows aria-hidden", () => {
    const container = renderCard();
    expect(
      container.querySelector(".stock-indicator").getAttribute("aria-hidden")
    ).toBe("true");
    expect(
      container.querySelector(".stock-ticker-label").getAttribute("aria-hidden")
    ).toBe("true");
  });

  it("exposes a localized screen-reader label with the formatted change and price", () => {
    const container = renderCard();
    const sr = container.querySelector(".stock-ticker-sr");
    expect(sr.getAttribute("data-l10n-id")).toBe(
      "newtab-stocks-ticker-status-up"
    );
    const args = JSON.parse(sr.getAttribute("data-l10n-args"));
    expect(args).toEqual({
      name: "SPDR S&P 500 ETF Trust",
      change: "+2.1%",
      price: "$559.44",
    });
  });

  it("uses the direction-specific screen-reader message id", () => {
    const down = render(
      <StockTicker name="n" ticker="IWM" price="$1 USD" changePercent="-0.21" />
    ).container;
    expect(
      down.querySelector(".stock-ticker-sr").getAttribute("data-l10n-id")
    ).toBe("newtab-stocks-ticker-status-down");
    const flat = render(
      <StockTicker name="n" ticker="DIA" price="$1 USD" changePercent="0.00" />
    ).container;
    expect(
      flat.querySelector(".stock-ticker-sr").getAttribute("data-l10n-id")
    ).toBe("newtab-stocks-ticker-status-flat");
  });

  it("renders as an aria-hidden placeholder with no screen-reader label while loading", () => {
    const { container } = render(<StockTicker loading={true} />);
    expect(container.querySelector(".stock-ticker-sr")).toBeNull();
    expect(
      container.querySelector("li.stock-ticker").getAttribute("aria-hidden")
    ).toBe("true");
  });

  it("falls back to the ticker symbol as the screen-reader subject when name is missing, and is not aria-hidden", () => {
    const { container } = render(
      <StockTicker
        name=""
        ticker="SPY"
        price="$559.44 USD"
        changePercent="+2.1"
      />
    );
    const sr = container.querySelector(".stock-ticker-sr");
    expect(sr.getAttribute("data-l10n-id")).toBe(
      "newtab-stocks-ticker-status-up"
    );
    const args = JSON.parse(sr.getAttribute("data-l10n-args"));
    expect(args.name).toBe("SPY");
    expect(
      container.querySelector("li.stock-ticker").getAttribute("aria-hidden")
    ).toBeNull();
  });

  it("uses the medium layout with no name by default", () => {
    const container = renderCard();
    expect(container.querySelector(".stock-ticker--medium")).toBeTruthy();
    expect(container.querySelector(".stock-ticker-name")).toBeNull();
  });

  it("renders the large layout: full name plus ticker, then change and price", () => {
    const { container } = render(
      <StockTicker
        size="large"
        name="SPDR S&P 500 ETF Trust"
        ticker="SPY"
        price="$559.44 USD"
        changePercent="+2.1"
      />
    );
    expect(container.querySelector(".stock-ticker--large")).toBeTruthy();
    expect(container.querySelector(".stock-ticker-name").textContent).toBe(
      "SPDR S&P 500 ETF Trust"
    );
    expect(container.querySelector(".stock-ticker-symbol").textContent).toBe(
      "SPY"
    );
    expect(container.querySelector(".stock-ticker-price").textContent).toBe(
      "$559.44"
    );
    const args = JSON.parse(
      container.querySelector(".stock-ticker-sr").getAttribute("data-l10n-args")
    );
    expect(args).toEqual({
      name: "SPDR S&P 500 ETF Trust",
      change: "+2.1%",
      price: "$559.44",
    });
  });
});
