﻿const { useEffect, useState } = React;

function formatValue(value) {
  if (value === null || value === undefined || value === "") {
    return "-";
  }

  return String(value);
}

function formatTime(value) {
  if (!value) {
    return "-";
  }

  const date = new Date(value);
  if (isNaN(date.getTime())) {
    return String(value);
  }

  return date.toLocaleString(undefined, {
    year: "numeric",
    month: "short",
    day: "numeric",
    hour: "numeric",
    minute: "2-digit",
    second: "2-digit",
  });
}

function formatPrice(value) {
  if (value === null || value === undefined || value === "") {
    return "-";
  }

  const numberValue = Number(value);
  return Number.isFinite(numberValue) ? numberValue.toFixed(2) : String(value);
}

function formatRupees(value) {
  if (value === null || value === undefined || value === "") {
    return "-";
  }
  const num = Number(value);
  if (!Number.isFinite(num)) {
    return String(value);
  }
  return num.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
}

function formatSide(value) {
  if (Number(value) === 1) {
    return "Buy";
  }

  if (Number(value) === -1) {
    return "Sell";
  }

  return formatValue(value);
}

function SummaryCard({ label, value, subtext }) {
  return (
    <div className="summary-card">
      <div className="summary-label">{label}</div>
      <div className="summary-value">{value}</div>
      {subtext ? <div className="summary-subtext">{subtext}</div> : null}
    </div>
  );
}

function SimpleTable({ columns, rows }) {
  if (!rows || rows.length === 0) {
    return <div className="empty-state">No records yet.</div>;
  }

  return (
    <div className="table-wrap">
      <table className="table">
        <thead>
          <tr>
            {columns.map((column) => (
              <th key={column.key}>{column.label}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {rows.map((row, index) => (
            <tr key={row.id || row.alert_timestamp || row.order_timestamp || row.entry_timestamp || index}>
              {columns.map((column) => (
                <td key={column.key}>
                  {column.render ? column.render(row[column.key], row) : formatValue(row[column.key])}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

async function readJsonResponse(response) {
  const contentType = response.headers.get("content-type") || "";
  const responseText = await response.text();

  if (!responseText) {
    return {};
  }

  if (!contentType.includes("application/json")) {
    throw new Error(responseText.slice(0, 180) || "API returned a non-JSON response.");
  }

  try {
    return JSON.parse(responseText);
  } catch (error) {
    throw new Error("API returned invalid JSON.");
  }
}

function formatErrorMessage(message) {
  const text = String(message || "").trim();

  if (!text) {
    return "Unable to load the dashboard.";
  }

  if (text.includes("FYERS access token expired at")) {
    const expiryText = text.replace("FYERS access token expired at ", "").replace(/\. Generate a fresh token.*$/, "");
    return `FYERS token expired. Please update the token. Expired at: ${expiryText}`;
  }

  if (text.includes("Request failed with status code 401") || text.includes("401 Unauthorized")) {
    return "FYERS token expired or invalid. Please update the token.";
  }

  return text;
}

function App() {
  const [dashboard, setDashboard] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState("");
  const [notice, setNotice] = useState("");
  const latestTimeRef = React.useRef("");
  const isRequestInFlightRef = React.useRef(false);

  async function loadDashboard() {
    if (isRequestInFlightRef.current) {
      return;
    }
    isRequestInFlightRef.current = true;
    setLoading(true);

    try {
      let queryStr = window.location.search || "";
      if (latestTimeRef.current) {
        const sep = queryStr ? "&" : "?";
        queryStr += sep + "since=" + encodeURIComponent(latestTimeRef.current);
      }

      const response = await fetch("/api/dashboard" + queryStr);
      const data = await readJsonResponse(response);

      if (!response.ok) {
        throw new Error(data.error || "Unable to load dashboard.");
      }

      setDashboard((prevDashboard) => {
        const incomingRows = data?.candles?.rows || [];
        const sortCandlesAscending = (rows) =>
          [...rows].sort((a, b) => new Date(a.candle_timestamp) - new Date(b.candle_timestamp));
        const getRollingWindow = (rows) => sortCandlesAscending(rows).slice(-10);

        if (!prevDashboard || !data.candles) {
          if (incomingRows.length) {
            const sortedIncomingRows = sortCandlesAscending(incomingRows);
            latestTimeRef.current = sortedIncomingRows[sortedIncomingRows.length - 1].candle_timestamp;
            data.candles.rows = sortedIncomingRows.slice(-10);
          }
          return data;
        }

        if (!incomingRows.length) {
          data.candles.rows = (prevDashboard.candles?.rows || []).slice(-10);
          return data;
        }

        const sortedIncomingRows = sortCandlesAscending(incomingRows);
        latestTimeRef.current = sortedIncomingRows[sortedIncomingRows.length - 1].candle_timestamp;
        const mergedRows = [...(prevDashboard.candles?.rows || []), ...incomingRows];
        const uniqueRowsMap = new Map();
        sortCandlesAscending(mergedRows).forEach((row) => {
          uniqueRowsMap.set(row.candle_timestamp, row);
        });

        data.candles.rows = getRollingWindow(Array.from(uniqueRowsMap.values()));

        return data;
      });

      setNotice(data.configIssue?.message || "");
      setError("");
    } catch (loadError) {
      setError(formatErrorMessage(loadError.message || "Unable to load dashboard."));
      setNotice("");
    } finally {
      isRequestInFlightRef.current = false;
      setLoading(false);
    }
  }

  useEffect(() => {
    loadDashboard();
    const timer = setInterval(loadDashboard, 1000);
    return () => clearInterval(timer);
  }, []);

  const market = dashboard?.market;
  const setup = dashboard?.setup;
  const strategy = dashboard?.strategy;
  const runtime = dashboard?.runtime || {};
  const scheduler = dashboard?.scheduler || {};

  return (
    <div className="app-shell">
      {error ? <div className="message-banner message-error">{error}</div> : null}
      {notice ? <div className="message-banner message-note">{notice}</div> : null}

      <section className="summary-grid">
        <SummaryCard
          label="Scheduler"
          value={scheduler?.enabled ? `${formatValue(dashboard?.candles?.summary?.timeframeMinutes)} Minute Live Polling` : "Stopped"}
          subtext={`Started: ${formatValue(scheduler?.startedAt)}`}
        />
        <SummaryCard
          label="Last Completed Check"
          value={formatValue(scheduler.lastCompletedAt || runtime.finishedAt)}
          subtext={`Last trigger: ${formatValue(runtime.lastTrigger)}`}
        />
        <SummaryCard
          label="Tracked Symbol"
          value={formatValue(market?.symbolName)}
          subtext={`${formatValue(market?.tradeSymbol)} | NIFTY Spot: ${formatPrice(market?.spotPrice)}`}
        />
        <SummaryCard
          label="Current Setup"
          value={formatValue(setup?.statusText || "No setup yet")}
          subtext={`Current candle: ${formatValue(setup?.currentCandleTime)}`}
        />
      </section>

      <section className="panel section-space" style={{ overflowX: "auto" }}>
        <div className="panel-head">
          <h2>Latest 10 candles</h2>
        </div>
        <SimpleTable
          columns={[
            { key: "candle_timestamp", label: "Timestamp", render: (value) => formatTime(value) },
            { key: "open_price", label: "Open", render: (value) => formatPrice(value) },
            { key: "high_price", label: "High", render: (value) => formatPrice(value) },
            { key: "low_price", label: "Low", render: (value) => formatPrice(value) },
            { key: "close_price", label: "Close", render: (value) => formatPrice(value) },
            { key: "volume", label: "Volume", render: (value) => formatValue(value) },
          ]}
          rows={dashboard?.candles?.rows || []}
        />
      </section>

      <section className="panel section-space" style={{ overflowX: "auto" }}>
        <div className="panel-head">
          <h2>Trade alert check</h2>
        </div>
        <SimpleTable
          columns={[
            { key: "currentCandleTime", label: "Current Candle Time", render: (value) => formatTime(value) },
            { key: "currentOpen", label: "Current Open", render: (value) => formatPrice(value) },
            { key: "currentHigh", label: "Current High", render: (value) => formatPrice(value) },
            { key: "currentLow", label: "Current Low", render: (value) => formatPrice(value) },
            { key: "currentClose", label: "Current Close", render: (value) => formatPrice(value) },
            { key: "previousTenHigh", label: "Previous 9 High", render: (value) => formatPrice(value) },
            { key: "isGreenCandle", label: "Green Candle", render: (value) => String(Boolean(value)) },
            { key: "isBreakout", label: "Breakout", render: (value) => String(Boolean(value)) },
            { key: "shouldBuy", label: "Should Buy", render: (value) => String(Boolean(value)) },
          ]}
          rows={dashboard?.setup ? [dashboard.setup] : []}
        />
      </section>
      <section className="panel section-space" style={{ overflowX: "auto" }}>
        <div className="panel-head">
          <h2>Order details</h2>
        </div>
        {dashboard?.strategy?.pnlSummary ? (
          <div className="pnl-summary">
            <div>Lot size: {dashboard.strategy.pnlSummary.lotSize} | Brokerage/leg: ₹{dashboard.strategy.pnlSummary.brokeragePerLeg.toFixed ? dashboard.strategy.pnlSummary.brokeragePerLeg.toFixed(2) : dashboard.strategy.pnlSummary.brokeragePerLeg}</div>
            <div>Trades: {dashboard.strategy.pnlSummary.trades}</div>
            <div>Gross: ₹{formatRupees(dashboard.strategy.pnlSummary.totalGross)} | Brokerage: ₹{formatRupees(dashboard.strategy.pnlSummary.totalBrokerage)} | Net: <strong>₹{formatRupees(dashboard.strategy.pnlSummary.totalNet)}</strong> ({formatPrice(dashboard.strategy.pnlSummary.totalPoints)} pts)</div>
          </div>
        ) : null}
        <SimpleTable
          columns={[
            { key: "symbol_name", label: "Trade Symbol", render: (value, row) => formatValue(row.trade_symbol || value) },
            { key: "position_side", label: "Side", render: (value) => formatSide(value) },
            { key: "entry_timestamp", label: "Buy/Sell Time", render: (value) => formatTime(value) },
            { key: "entry_price", label: "Entry", render: (value) => formatPrice(value) },
            { key: "stop_loss", label: "Stop Loss", render: (value) => formatPrice(value) },
            { key: "exit_price", label: "Exit", render: (value) => formatPrice(value) },
            { key: "exit_timestamp", label: "Exit Time", render: (value) => formatTime(value) },
            { key: "quantity", label: "Qty", render: (value) => formatValue(value) },
            { key: "points", label: "Pts", render: (value) => formatPrice(value) },
            { key: "gross_pnl", label: "Gross ₹", render: (value) => formatRupees(value) },
            { key: "brokerage", label: "Brokerage ₹", render: (value) => formatRupees(value) },
            { key: "net_pnl", label: "Net ₹", render: (value) => formatRupees(value) },
            { key: "status", label: "Status", render: (value) => formatValue(value) },
          ]}
          rows={strategy?.recentPositions || []}
        />
      </section>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
