import React, { useState, useEffect, useRef, useCallback } from "react";
import FilterBar from "./FilterBar";
import SQLPreview from "./SQLPreview";
import NumberView from "./NumberView";
import GroupByView from "./GroupByView";
import { pgFetchColumns, pgQuery } from "./api";

function shouldHighlight(row, highlightText, options = {}) {
  if (!highlightText) return false;
  const { caseSensitive, wholeWord, regex } = options;
  return Object.values(row).some((v) => {
    if (v == null) return false;
    const cellStr = String(v);
    if (regex) {
      try {
        const flags = caseSensitive ? "" : "i";
        const pattern = wholeWord ? `\\b${highlightText}\\b` : highlightText;
        return new RegExp(pattern, flags).test(cellStr);
      } catch { return false; }
    }
    if (wholeWord) {
      const flags = caseSensitive ? "" : "i";
      try {
        return new RegExp(`\\b${highlightText.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`, flags).test(cellStr);
      } catch { return false; }
    }
    if (caseSensitive) return cellStr.includes(highlightText);
    return cellStr.toLowerCase().includes(highlightText.toLowerCase());
  });
}

const btnStyle = (enabled) => ({
  background: "none",
  border: "1px solid var(--border)",
  borderRadius: 4,
  padding: "2px 8px",
  color: enabled ? "var(--text)" : "var(--text-dim)",
  cursor: enabled ? "pointer" : "default",
  fontFamily: "inherit",
  fontSize: 11,
  opacity: enabled ? 1 : 0.4,
});

function aggParams(viewMode, viewConfig) {
  if (viewMode === "number") {
    return {
      view_mode: "number",
      aggregation: viewConfig?.aggregation || "count",
      agg_column: viewConfig?.column || null,
    };
  }
  if (viewMode === "chart") {
    return {
      view_mode: "chart",
      aggregation: viewConfig?.aggregation || "count",
      group_by_column: viewConfig?.groupByColumn || null,
      value_column: viewConfig?.valueColumn || null,
    };
  }
  return {};
}

// Compute linked filter string from parent panels' selectedRow
function computeLinkedFilters(links, allPanels) {
  const parts = [];
  for (const link of links) {
    const parent = allPanels.find((p) => p.id === link.parentPanelId);
    if (!parent?.selectedRow) continue;
    for (const m of link.mappings) {
      const val = parent.selectedRow[m.parentColumn];
      if (val != null) {
        parts.push({ column: m.childColumn, value: String(val), parentColumn: m.parentColumn, parentName: parent.displayName });
      }
    }
  }
  return parts;
}

// Build include filter string from linked filter entries (exact match with = prefix)
function linkedFiltersToInclude(linkedFilters) {
  return linkedFilters.map((f) => `${f.column}:=${f.value}`).join(", ");
}

// Merge user include with linked filters into a single include string
function mergeIncludes(userInclude, linkedFilters) {
  const linked = linkedFiltersToInclude(linkedFilters);
  if (!linked) return userInclude;
  if (!userInclude || !userInclude.trim()) return linked;
  return `${userInclude}, ${linked}`;
}

export default function PostgresTabContent({ tab, updateTab, allPanels = [], pageSize, setError, refreshKey, locked }) {
  const debounceRef = useRef(null);
  const pageSizeRef = useRef(pageSize);
  pageSizeRef.current = pageSize;
  const initialRefreshKey = useRef(refreshKey);

  // Fetch columns on mount
  useEffect(() => {
    if (tab.columns.length > 0) return;
    pgFetchColumns(tab.instanceId, tab.schema, tab.name)
      .then((data) => updateTab({ columns: data.columns }))
      .catch((e) => setError(e.message));
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  // Auto-query when columns load
  useEffect(() => {
    if (tab.columns.length === 0 || tab.results) return;
    runQuery(tab, 0);
  }, [tab.columns.length]); // eslint-disable-line react-hooks/exhaustive-deps

  // Refresh All
  useEffect(() => {
    if (refreshKey === initialRefreshKey.current) return;
    runQuery(tab, tab.page);
  }, [refreshKey]); // eslint-disable-line react-hooks/exhaustive-deps

  // Re-query when view mode or config changes
  const prevViewRef = useRef({ viewMode: tab.viewMode, viewConfig: tab.viewConfig });
  useEffect(() => {
    const prev = prevViewRef.current;
    const cur = { viewMode: tab.viewMode, viewConfig: tab.viewConfig };
    prevViewRef.current = cur;
    if (tab.columns.length === 0) return;
    if (JSON.stringify(prev) === JSON.stringify(cur)) return;
    runQuery(tab, 0);
  }, [tab.viewMode, tab.viewConfig]); // eslint-disable-line react-hooks/exhaustive-deps

  // Compute linked filters from parent panels
  const linkedFilters = computeLinkedFilters(tab.links || [], allPanels);
  const linkedFilterKey = JSON.stringify(linkedFilters);

  // Re-query when linked filters change (parent row selection changed)
  const prevLinkedRef = useRef(linkedFilterKey);
  useEffect(() => {
    if (prevLinkedRef.current === linkedFilterKey) return;
    prevLinkedRef.current = linkedFilterKey;
    if (tab.columns.length === 0) return;
    runQuery(tab, 0);
  }, [linkedFilterKey]); // eslint-disable-line react-hooks/exhaustive-deps

  const runQuery = useCallback((t, page = 0) => {
    const ps = pageSizeRef.current;
    const vm = t.viewMode || "table";
    const currentLinked = computeLinkedFilters(t.links || [], allPanels);
    const effectiveInclude = mergeIncludes(t.filters.include, currentLinked);
    updateTab({ loading: true });
    setError(null);
    pgQuery(t.instanceId, {
      schema: t.schema,
      table: t.name,
      include: effectiveInclude,
      exclude: t.filters.exclude,
      highlight: t.filters.highlight,
      columns: t.filters.columns,
      limit: ps,
      offset: page * ps,
      ...aggParams(vm, t.viewConfig),
    })
      .then((results) => updateTab({ results, loading: false }))
      .catch((e) => {
        setError(e.message);
        updateTab({ loading: false });
      });
  }, [updateTab, setError, allPanels]);

  const handleFilterChange = (key, value) => {
    const newFilters = { ...tab.filters, [key]: value };
    updateTab({ filters: newFilters });
    if (debounceRef.current) clearTimeout(debounceRef.current);
    debounceRef.current = setTimeout(() => {
      const currentLinked = computeLinkedFilters(tab.links || [], allPanels);
      const effectiveInclude = mergeIncludes(key === "include" ? value : tab.filters.include, currentLinked);
      updateTab({ page: 0, loading: true });
      setError(null);
      pgQuery(tab.instanceId, {
        schema: tab.schema,
        table: tab.name,
        include: effectiveInclude,
        exclude: key === "exclude" ? value : tab.filters.exclude,
        highlight: key === "highlight" ? value : tab.filters.highlight,
        columns: key === "columns" ? value : tab.filters.columns,
        limit: pageSizeRef.current,
        offset: 0,
        ...aggParams(tab.viewMode || "table", tab.viewConfig),
      })
        .then((results) => updateTab({ results, loading: false }))
        .catch((e) => {
          setError(e.message);
          updateTab({ loading: false });
        });
    }, 300);
  };

  const handlePageChange = (newPage) => {
    updateTab({ page: newPage });
    runQuery({ ...tab, page: newPage }, newPage);
  };

  const handleRowClick = (row) => {
    // Toggle selection: if the same row is clicked again, deselect
    const isSame = tab.selectedRow && Object.keys(row).every((k) => tab.selectedRow[k] === row[k]);
    updateTab({ selectedRow: isSame ? null : row });
  };

  const isRowSelected = (row) => {
    if (!tab.selectedRow) return false;
    return Object.keys(row).every((k) => tab.selectedRow[k] === row[k]);
  };

  const rows = tab.results?.rows;
  const columns = rows && rows.length > 0 ? Object.keys(rows[0]) : [];
  const totalCount = tab.results?.total_count;
  const totalPages = totalCount != null ? Math.ceil(totalCount / pageSize) : 0;
  const hasPrev = tab.page > 0;
  const hasNext = totalCount != null && (tab.page + 1) * pageSize < totalCount;
  const rangeStart = tab.page * pageSize + 1;
  const rangeEnd = tab.page * pageSize + (rows?.length || 0);
  const viewMode = tab.viewMode || "table";

  return (
    <div style={{ display: "flex", flexDirection: "column", flex: 1, overflow: "hidden" }}>
      {/* Linked filter pills */}
      {linkedFilters.length > 0 && viewMode === "table" && (
        <div
          style={{
            display: "flex",
            alignItems: "center",
            gap: 6,
            padding: "6px 20px",
            background: "rgba(34, 211, 238, 0.04)",
            borderBottom: "1px solid var(--border)",
            flexWrap: "wrap",
            fontSize: 11,
          }}
        >
          <span style={{ color: "var(--cyan)", fontWeight: 600, fontSize: 10, flexShrink: 0 }}>LINKED</span>
          {linkedFilters.map((f, i) => (
            <span
              key={i}
              style={{
                background: "rgba(34, 211, 238, 0.10)",
                border: "1px solid rgba(34, 211, 238, 0.25)",
                borderRadius: 4,
                padding: "2px 8px",
                color: "var(--cyan)",
                whiteSpace: "nowrap",
              }}
            >
              {f.column} = {f.value}
            </span>
          ))}
          <span style={{ color: "var(--text-dim)", fontSize: 10, marginLeft: 4 }}>
            from {linkedFilters[0]?.parentName}
          </span>
        </div>
      )}
      {tab.filtersVisible !== false && tab.columns.length > 0 && viewMode === "table" && (
        <FilterBar
          filters={tab.filters}
          onFilterChange={handleFilterChange}
          columns={tab.columns}
          highlightOptions={tab.highlightOptions}
          onHighlightOptionToggle={(key) =>
            updateTab({ highlightOptions: { ...tab.highlightOptions, [key]: !tab.highlightOptions[key] } })
          }
          onRefresh={() => runQuery(tab, tab.page)}
        />
      )}
      {tab.filtersVisible !== false && viewMode === "table" && <SQLPreview sql={tab.results?.sql} />}

      {/* Number view */}
      {viewMode === "number" && tab.results?.view_mode === "number" && (
        <NumberView results={tab.results} config={tab.viewConfig} tableName={tab.displayName} />
      )}
      {viewMode === "number" && !tab.results && (
        <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", color: "var(--text-dim)" }}>Loading...</div>
      )}

      {/* Chart (group-by) view */}
      {viewMode === "chart" && tab.results?.view_mode === "chart" && (
        <GroupByView
          results={tab.results}
          config={tab.viewConfig}
          tableName={tab.displayName}
          chartType={tab.chartType || "hbar"}
        />
      )}
      {viewMode === "chart" && !tab.results && (
        <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", color: "var(--text-dim)" }}>Loading...</div>
      )}

      {/* Table view */}
      {viewMode === "table" && rows && (
        <div style={{ flex: 1, overflow: "auto", position: "relative" }}>
          <div
            style={{
              padding: "8px 20px",
              fontSize: 11,
              color: "var(--text-dim)",
              borderBottom: "1px solid var(--border)",
              background: "var(--panel)",
              position: "sticky",
              top: 0,
              zIndex: 10,
              display: "flex",
              justifyContent: "space-between",
              alignItems: "center",
            }}
          >
            <span>
              {rows.length > 0 ? `${rangeStart}–${rangeEnd} of ${totalCount ?? "?"}` : `0 of ${totalCount ?? "?"}`}
            </span>
            <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
            {locked && viewMode === "table" && (
              <button
                onClick={() => updateTab({ filtersVisible: tab.filtersVisible === false ? true : false })}
                title={tab.filtersVisible !== false ? "Hide filters" : "Show filters"}
                style={{
                  background: tab.filtersVisible !== false ? "rgba(255,255,255,0.04)" : "none",
                  border: "1px solid var(--border)",
                  borderRadius: 4,
                  color: tab.filtersVisible !== false ? "var(--text)" : "var(--text-dim)",
                  fontSize: 10,
                  padding: "1px 6px",
                  cursor: "pointer",
                  display: "flex",
                  alignItems: "center",
                  gap: 3,
                }}
                onMouseEnter={(e) => { e.currentTarget.style.borderColor = "var(--text-dim)"; }}
                onMouseLeave={(e) => { e.currentTarget.style.borderColor = "var(--border)"; }}
              >
                <span style={{ fontSize: 8 }}>{tab.filtersVisible !== false ? "\u25BE" : "\u25B8"}</span>
                <span>filters</span>
              </button>
            )}
            {totalPages > 1 && (
              <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                <button style={btnStyle(hasPrev)} disabled={!hasPrev} onClick={() => hasPrev && handlePageChange(tab.page - 1)}>Prev</button>
                <span>{tab.page + 1} / {totalPages}</span>
                <button style={btnStyle(hasNext)} disabled={!hasNext} onClick={() => hasNext && handlePageChange(tab.page + 1)}>Next</button>
              </div>
            )}
            </div>
          </div>
          {rows.length === 0 ? (
            <div style={{ padding: 40, textAlign: "center", color: "var(--text-dim)" }}>No results</div>
          ) : (
            <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 12 }}>
              <thead>
                <tr>
                  {columns.map((col) => (
                    <th
                      key={col}
                      style={{
                        position: "sticky",
                        top: 33,
                        background: "var(--bg)",
                        padding: "8px 12px",
                        textAlign: "left",
                        fontWeight: 600,
                        fontSize: 11,
                        textTransform: "uppercase",
                        letterSpacing: "0.05em",
                        color: "var(--text-dim)",
                        borderBottom: "1px solid var(--border)",
                        whiteSpace: "nowrap",
                        zIndex: 5,
                      }}
                    >
                      {col}
                    </th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {rows.map((row, i) => {
                  const highlighted = shouldHighlight(row, tab.filters.highlight, tab.highlightOptions);
                  const selected = isRowSelected(row);
                  const bgDefault = selected ? "rgba(34, 211, 238, 0.10)" : highlighted ? "var(--highlight-row)" : i % 2 === 1 ? "var(--row-alt)" : "transparent";
                  const borderColor = selected ? "var(--cyan)" : highlighted ? "var(--yellow)" : "transparent";
                  return (
                    <tr
                      key={i}
                      onClick={() => handleRowClick(row)}
                      style={{
                        background: bgDefault,
                        borderLeft: `3px solid ${borderColor}`,
                        cursor: "pointer",
                      }}
                      onMouseEnter={(e) => { if (!selected && !highlighted) e.currentTarget.style.background = "var(--row-hover)"; }}
                      onMouseLeave={(e) => { e.currentTarget.style.background = bgDefault; }}
                    >
                      {columns.map((col) => (
                        <td
                          key={col}
                          style={{
                            padding: "6px 12px",
                            borderBottom: "1px solid var(--border)",
                            whiteSpace: "nowrap",
                            maxWidth: 300,
                            overflow: "hidden",
                            textOverflow: "ellipsis",
                          }}
                        >
                          {row[col] === null ? (
                            <span style={{ color: "var(--text-dim)", fontStyle: "italic" }}>null</span>
                          ) : (
                            String(row[col])
                          )}
                        </td>
                      ))}
                    </tr>
                  );
                })}
              </tbody>
            </table>
          )}
        </div>
      )}
    </div>
  );
}
