(function initPortfolioSecurities(global) {
  const portfolioSelection = global.PortfolioSelection;
  if (!portfolioSelection) {
    throw new Error('PortfolioSelection must be loaded before PortfolioSecurities.');
  }

  const {
    getAuthorizedJsonHeaders,
    handleUnauthorizedApiResponse
  } = portfolioSelection;

  function parseSearchValues(value) {
    return Array.from(new Set(
      String(value || '')
        .split(/[\n,]+/)
        .map((item) => item.trim())
        .filter(Boolean)
    ));
  }

  function hasAdditionalDetails(value) {
    if (Array.isArray(value)) {
      return value.length > 0;
    }
    if (value && typeof value === 'object') {
      return Object.keys(value).length > 0;
    }
    return false;
  }

  function toText(value) {
    if (value == null || value === '') {
      return '-';
    }
    return String(value);
  }

  function rowKeyForResult(item, index) {
    return String(item && (item.id || item.identifier || item.isin || item.ticker || item.name || index));
  }

  function toLocalCopyText(item) {
    return item && item.noLocalCopy ? 'No' : 'Yes';
  }

  function getLocalCopyClassName(item) {
    return item && item.noLocalCopy
      ? 'securities-local-copy-chip securities-local-copy-chip-missing'
      : 'securities-local-copy-chip securities-local-copy-chip-present';
  }

  function buildResultsFromPayload(payload) {
    const lookupType = String(payload && payload.lookupType || 'Ticker');
    const mappedRows = Array.isArray(payload && payload.securities)
      ? payload.securities.map((item) => ({
        id: item.id,
        ticker: item.ticker,
        isin: item.isin,
        figi: item.figi,
        name: item.name,
        noLocalCopy: item && item.noLocalCopy === true,
        additionalDetails: item && item.additionalDetails != null ? item.additionalDetails : null
      }))
      : [];

    const mappedSyntheticIdentifierSet = new Set(
      mappedRows
        .filter((item) => item && item.noLocalCopy)
        .map((item) => {
          if (lookupType === 'Ticker') {
            return String(item && item.ticker || '').trim().toUpperCase();
          }

          if (lookupType === 'Name') {
            return String(item && item.name || '').trim().toLowerCase();
          }

          return String(item && item.isin || '').trim().toUpperCase();
        })
        .filter(Boolean)
    );

    const unmappedRows = Array.isArray(payload && payload.unmapped)
      ? payload.unmapped
        .filter((identifier) => {
          const normalized = lookupType === 'Name'
            ? String(identifier || '').trim().toLowerCase()
            : String(identifier || '').trim().toUpperCase();
          return normalized && !mappedSyntheticIdentifierSet.has(normalized);
        })
        .map((identifier) => ({
          id: null,
          identifier,
          ticker: lookupType === 'Ticker' ? identifier : null,
          isin: lookupType === 'ISIN' ? identifier : null,
          figi: null,
          name: lookupType === 'Name' ? identifier : null,
          noLocalCopy: true,
          additionalDetails: null
        }))
      : [];

    return mappedRows.concat(unmappedRows);
  }

  function AdditionalDetailsView({ value }) {
    if (!hasAdditionalDetails(value)) {
      return null;
    }

    if (Array.isArray(value)) {
      if (value.length === 0) {
        return null;
      }

      const columns = Array.from(new Set(
        value
          .filter((item) => item && typeof item === 'object')
          .flatMap((item) => Object.keys(item))
      ));

      if (columns.length === 0) {
        return (
          <pre className="securities-details-pre">{JSON.stringify(value, null, 2)}</pre>
        );
      }

      return (
        <div className="upload-table-wrap">
          <table className="transactions-table securities-details-table">
            <thead>
              <tr>
                {columns.map((column) => (
                  <th key={column}>{column}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {value.map((item, rowIndex) => (
                <tr key={rowIndex}>
                  {columns.map((column) => (
                    <td key={column}>{toText(item && item[column])}</td>
                  ))}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      );
    }

    return (
      <pre className="securities-details-pre">{JSON.stringify(value, null, 2)}</pre>
    );
  }

  function SecuritiesModulePage() {
    const [searchInput, setSearchInput] = React.useState('');
    const [searchType, setSearchType] = React.useState('Ticker');
    const [isLoading, setIsLoading] = React.useState(false);
    const [status, setStatus] = React.useState(null);
    const [lookupType, setLookupType] = React.useState('');
    const [results, setResults] = React.useState([]);
    const [expandedRows, setExpandedRows] = React.useState({});

    const submitSearch = async (event) => {
      event.preventDefault();
      const identifiers = parseSearchValues(searchInput);
      if (identifiers.length === 0) {
        const valueLabel = searchType === 'Name' ? 'name' : (searchType === 'ISIN' ? 'ISIN' : 'ticker');
        setStatus({ type: 'error', message: `Enter at least one ${valueLabel}.` });
        setResults([]);
        setLookupType('');
        setExpandedRows({});
        return;
      }

      setIsLoading(true);
      setStatus(null);
      setExpandedRows({});

      try {
        const queryKey = searchType === 'Name' ? 'names' : (searchType === 'ISIN' ? 'isins' : 'tickers');
        const response = await fetch(`/api/securities?${queryKey}=${encodeURIComponent(identifiers.join(','))}`, {
          method: 'GET',
          headers: getAuthorizedJsonHeaders()
        });

        if (response.status === 401 || response.status === 403) {
          handleUnauthorizedApiResponse();
          return;
        }

        if (!response.ok) {
          const payload = await response.json().catch(() => ({}));
          const errorCode = payload && payload.code != null ? payload.code : 'Unknown';
          setStatus({ type: 'error', message: `Securities lookup failed. Technical Code = ${errorCode}.` });
          setResults([]);
          return;
        }

        const payload = await response.json().catch(() => ({}));
        const nextResults = buildResultsFromPayload(payload);
        setLookupType(String(payload.lookupType || 'Ticker'));
        setResults(nextResults);
        setStatus({ type: 'success', message: `${nextResults.length} result(s) returned.` });
      } catch (error) {
        setStatus({ type: 'error', message: 'Securities lookup failed. Please try again.' });
        setResults([]);
      } finally {
        setIsLoading(false);
      }
    };

    const toggleExpanded = (key) => {
      setExpandedRows((current) => Object.assign({}, current, { [key]: !current[key] }));
    };

    return (
      <div className="content auth-shell securities-page-shell">
        <section className="hero-card securities-hero-card">
          <div className="securities-hero-copy-block">
            <h1 className="hero-title securities-hero-title">Securities</h1>
            <p className="hero-copy">Search by ticker or name and review securities and local copy status.</p>
          </div>
          <form className="form-grid securities-search-form" onSubmit={submitSearch}>
            <label className="field">
              <span>Search Type</span>
              <select
                value={searchType}
                onChange={(event) => {
                  const nextValue = event.target.value;
                  setSearchType(nextValue === 'Name' || nextValue === 'ISIN' ? nextValue : 'Ticker');
                }}
              >
                <option value="Ticker">Ticker</option>
                <option value="ISIN">ISIN</option>
                <option value="Name">Name</option>
              </select>
            </label>
            <label className="field">
              <span>{searchType === 'Name' ? 'Names' : (searchType === 'ISIN' ? 'ISINs' : 'Tickers')}</span>
              <input
                type="text"
                placeholder={searchType === 'Name'
                  ? 'Apple Inc, Microsoft Corp'
                  : (searchType === 'ISIN' ? 'US0378331005, US5949181045' : 'AAPL, MSFT, VUSA')}
                value={searchInput}
                onChange={(event) => setSearchInput(event.target.value)}
              />
            </label>
            <div className="hero-actions securities-search-actions">
              <button className="primary-btn" type="submit" disabled={isLoading}>
                {isLoading ? 'Searching...' : 'Search Securities'}
              </button>
            </div>
          </form>
          {status ? (
            <div className={`status-message ${status.type}`} role="status">
              <span>{status.message}</span>
            </div>
          ) : null}
        </section>

        <section className="panel-card">
          <div className="securities-results-head">
            <h3 className="securities-results-title">Results</h3>
            <p className="muted securities-results-meta">
              {lookupType ? `Lookup Type: ${lookupType}` : 'Lookup Type: -'}
              {' · '}
              {`${results.length} row(s)`}
            </p>
          </div>
          <div className="upload-table-wrap">
            <table className="transactions-table securities-results-table">
              <thead>
                <tr>
                  <th className="txn-expand-column" aria-label="details" />
                  <th>Ticker</th>
                  <th>ISIN</th>
                  <th>FIGI</th>
                  <th>Name</th>
                  <th>Local Copy</th>
                </tr>
              </thead>
              <tbody>
                {results.length === 0 ? (
                  <tr>
                    <td colSpan={6} className="muted">No results yet. Run a search to see securities.</td>
                  </tr>
                ) : results.map((item, index) => {
                  const rowKey = rowKeyForResult(item, index);
                  const canExpand = hasAdditionalDetails(item && item.additionalDetails);
                  const isExpanded = !!expandedRows[rowKey];

                  return (
                    <React.Fragment key={rowKey}>
                      <tr>
                        <td className="txn-expand-column">
                          {canExpand ? (
                            <button
                              type="button"
                              className="txn-expand-toggle"
                              aria-expanded={isExpanded}
                              onClick={() => toggleExpanded(rowKey)}
                            >
                              {isExpanded ? '-' : '+'}
                            </button>
                          ) : <span className="txn-expand-placeholder"> </span>}
                        </td>
                        <td>{toText(item && item.ticker)}</td>
                        <td>{toText(item && item.isin)}</td>
                        <td>{toText(item && item.figi)}</td>
                        <td>{toText(item && item.name)}</td>
                        <td>
                          <span className={getLocalCopyClassName(item)}>{toLocalCopyText(item)}</span>
                        </td>
                      </tr>
                      {canExpand && isExpanded ? (
                        <tr>
                          <td colSpan={6}>
                            <AdditionalDetailsView value={item.additionalDetails} />
                          </td>
                        </tr>
                      ) : null}
                    </React.Fragment>
                  );
                })}
              </tbody>
            </table>
          </div>
        </section>
      </div>
    );
  }

  global.PortfolioSecurities = {
    SecuritiesModulePage
  };
})(window);
