import React, { useState, useMemo, useCallback, useEffect } from 'react'
import { useParams, useNavigate, useSearchParams } from 'react-router'
import { AlertTriangle, X, Search, Footprints, RotateCcw } from 'lucide-react'
import {
  DataTable,
  StatusDot,
  MonoText,
  Badge,
  useGlobalFilters,
} from '@cameleer/design-system'
import type { Column } from '@cameleer/design-system'
import {
  useSearchExecutions,
} from '../../api/queries/executions'
import { useEnvironmentStore } from '../../api/environment-store'
import type { ExecutionSummary } from '../../api/types'
import { attributeBadgeColor } from '../../utils/attribute-color'
import { parseAttrParam, formatAttrParam } from '../../utils/attribute-filter';
import type { AttributeFilter } from '../../utils/attribute-filter';
import { formatDuration, statusLabel } from '../../utils/format-utils'
import styles from './Dashboard.module.css'
import tableStyles from '../../styles/table-section.module.css'

// Row type extends ExecutionSummary with an `id` field for DataTable
interface Row extends ExecutionSummary {
  id: string
}

// ─── Helpers ─────────────────────────────────────────────────────────────────

function formatTimestamp(iso: string): string {
  const date = new Date(iso)
  const y = date.getFullYear()
  const mo = String(date.getMonth() + 1).padStart(2, '0')
  const d = String(date.getDate()).padStart(2, '0')
  const h = String(date.getHours()).padStart(2, '0')
  const mi = String(date.getMinutes()).padStart(2, '0')
  const s = String(date.getSeconds()).padStart(2, '0')
  return `${y}-${mo}-${d} ${h}:${mi}:${s}`
}

function statusToVariant(status: string): 'success' | 'error' | 'running' | 'warning' {
  switch (status) {
    case 'COMPLETED': return 'success'
    case 'FAILED': return 'error'
    case 'RUNNING': return 'running'
    default: return 'warning'
  }
}

function durationClass(ms: number, status: string): string {
  if (status === 'FAILED') return styles.durBreach
  if (ms < 100) return styles.durFast
  if (ms < 200) return styles.durNormal
  if (ms < 300) return styles.durSlow
  return styles.durBreach
}

// ─── Table columns ────────────────────────────────────────────────────────────

function buildColumns(hasAttributes: boolean): Column<Row>[] {
  return [
    {
      key: 'status',
      header: 'Status',
      width: '80px',
      render: (_: unknown, row: Row) => (
        <span className={styles.statusCell}>
          <StatusDot variant={statusToVariant(row.status)} />
          <MonoText size="xs">{statusLabel(row.status)}</MonoText>
          {row.hasTraceData && <Footprints size={11} color="var(--success)" style={{ marginLeft: 2, flexShrink: 0 }} />}
          {row.isReplay && <RotateCcw size={11} color="var(--amber)" style={{ marginLeft: 2, flexShrink: 0 }} />}
        </span>
      ),
    },
    ...(hasAttributes ? [{
      key: 'attributes' as const,
      header: 'Attributes',
      render: (_: unknown, row: Row) => {
        const attrs = row.attributes;
        if (!attrs || Object.keys(attrs).length === 0) return <span className={styles.muted}>—</span>;
        const entries = Object.entries(attrs);
        const shown = entries.slice(0, 2);
        const overflow = entries.length - 2;
        return (
          <div className={styles.attrCell}>
            {shown.map(([k, v]) => (
              <span key={k} title={k}>
                <Badge label={String(v)} color={attributeBadgeColor(k)} />
              </span>
            ))}
            {overflow > 0 && <span className={styles.attrOverflow}>+{overflow}</span>}
          </div>
        );
      },
    }] : []),
    {
      key: 'applicationId',
      header: 'App',
      sortable: true,
      render: (_: unknown, row: Row) => (
        <span className={styles.appName}>{row.applicationId ?? ''}</span>
      ),
    },
    {
      key: 'routeId',
      header: 'Route',
      sortable: true,
      render: (_: unknown, row: Row) => (
        <span className={styles.routeName}>{row.routeId}</span>
      ),
    },
    {
      key: 'startTime',
      header: 'Started',
      sortable: true,
      render: (_: unknown, row: Row) => (
        <MonoText size="xs">{formatTimestamp(row.startTime)}</MonoText>
      ),
    },
    {
      key: 'durationMs',
      header: 'Duration',
      sortable: true,
      render: (_: unknown, row: Row) => (
        <MonoText size="sm" className={durationClass(row.durationMs, row.status)}>
          {formatDuration(row.durationMs)}
        </MonoText>
      ),
    },
  ]
}

// ─── Dashboard component ─────────────────────────────────────────────────────

export interface SelectedExchange {
  executionId: string;
  applicationId: string;
  routeId: string;
}

interface DashboardProps {
  onExchangeSelect?: (exchange: SelectedExchange) => void;
  activeExchangeId?: string;
}

export default function Dashboard({ onExchangeSelect, activeExchangeId }: DashboardProps = {}) {
  const { appId, routeId } = useParams<{ appId: string; routeId: string }>()
  const navigate = useNavigate()
  const [searchParams, setSearchParams] = useSearchParams()
  const textFilter = searchParams.get('text') || undefined
  const attributeFilters = useMemo<AttributeFilter[]>(
    () => searchParams.getAll('attr')
              .map(parseAttrParam)
              .filter((f): f is AttributeFilter => f != null),
    [searchParams],
  );
  const [selectedId, setSelectedId] = useState<string | undefined>(activeExchangeId)
  const [sortField, setSortField] = useState<string>('startTime')
  const [sortDir, setSortDir] = useState<'asc' | 'desc'>('desc')

  // Sync selection from parent (survives remount when split view toggles)
  useEffect(() => {
    if (activeExchangeId !== undefined) setSelectedId(activeExchangeId);
  }, [activeExchangeId]);

  const selectedEnv = useEnvironmentStore((s) => s.environment);
  const { timeRange, statusFilters } = useGlobalFilters()
  const timeFrom = timeRange.start.toISOString()
  const timeTo = timeRange.end.toISOString()
  const handleSortChange = useCallback((key: string, dir: 'asc' | 'desc') => {
    setSortField(key)
    setSortDir(dir)
  }, [])

  // ─── API hooks ───────────────────────────────────────────────────────────
  // Convert design-system status filters (lowercase) to API status param (uppercase)
  const statusParam = statusFilters.size > 0
    ? [...statusFilters].map(s => s.toUpperCase()).join(',')
    : undefined

  const { data: searchResult } = useSearchExecutions(
    {
      timeFrom,
      timeTo,
      routeId: routeId || undefined,
      applicationId: appId || undefined,
      environment: selectedEnv,
      status: statusParam,
      text: textFilter,
      attributeFilters: attributeFilters.length > 0 ? attributeFilters : undefined,
      sortField,
      sortDir,
      offset: 0,
      limit: textFilter || attributeFilters.length > 0 ? 200 : 50,
    },
    !textFilter && attributeFilters.length === 0,
  )

  // ─── Rows ────────────────────────────────────────────────────────────────
  const rows: Row[] = useMemo(
    () => (searchResult?.data || []).map((e: ExecutionSummary) => ({ ...e, id: e.executionId })),
    [searchResult],
  )

  // ─── Table columns ──────────────────────────────────────────────────────
  const hasAttributes = rows.some(r => r.attributes && Object.keys(r.attributes).length > 0)
  const columns: Column<Row>[] = useMemo(() => buildColumns(hasAttributes), [hasAttributes])

  // ─── Row click → navigate to diagram view ────────────────────────────────

  function handleRowClick(row: Row) {
    setSelectedId(row.id)
    if (onExchangeSelect) {
      onExchangeSelect({
        executionId: row.executionId,
        applicationId: row.applicationId ?? '',
        routeId: row.routeId,
      })
    }
  }

  function handleRowAccent(row: Row): 'error' | 'warning' | undefined {
    if (row.status === 'FAILED') return 'error'
    return undefined
  }

  return (
    <div className={styles.content}>
      <div className={`${tableStyles.tableSection} ${styles.tableWrap}`}>
        <div className={tableStyles.tableHeader}>
          <span className={tableStyles.tableTitle}>
            {textFilter || attributeFilters.length > 0 ? (
              <>
                <Search size={14} style={{ marginRight: 4, verticalAlign: -2 }} />
                {textFilter && (
                  <>
                    Search: &ldquo;{textFilter}&rdquo;
                    <button
                      className={styles.clearSearch}
                      onClick={() => {
                        const next = new URLSearchParams(searchParams);
                        next.delete('text');
                        setSearchParams(next);
                      }}
                      title="Clear text search"
                    >
                      <X size={12} />
                    </button>
                  </>
                )}
                {attributeFilters.map((f, i) => (
                  <span key={`${f.key}:${f.value ?? ''}:${i}`} className={styles.attrChip}>
                    {f.value === undefined
                      ? <>has <code>{f.key}</code></>
                      : <><code>{f.key}</code> = <code>{f.value}</code></>}
                    <button
                      className={styles.clearSearch}
                      onClick={() => {
                        const next = new URLSearchParams(searchParams);
                        const remaining = next.getAll('attr')
                            .filter(a => a !== formatAttrParam(f));
                        next.delete('attr');
                        remaining.forEach(a => next.append('attr', a));
                        setSearchParams(next);
                      }}
                      title="Remove filter"
                    >
                      <X size={12} />
                    </button>
                  </span>
                ))}
              </>
            ) : 'Recent Exchanges'}
          </span>
          <div className={tableStyles.tableRight}>
            <span className={tableStyles.tableMeta}>
              {rows.length.toLocaleString()} of {(searchResult?.total ?? 0).toLocaleString()} exchanges
            </span>
            {!textFilter && attributeFilters.length === 0 && <Badge label="AUTO" color="success" />}
          </div>
        </div>

        <DataTable
          columns={columns}
          data={rows}
          onRowClick={handleRowClick}
          selectedId={selectedId}
          sortable
          flush
          fillHeight
          onSortChange={handleSortChange}
          rowAccent={handleRowAccent}
          expandedContent={(row: Row) =>
            row.errorMessage ? (
              <div className={styles.inlineError}>
                <span className={styles.inlineErrorIcon}><AlertTriangle size={14} /></span>
                <div>
                  <div className={styles.inlineErrorText}>{row.errorMessage}</div>
                  <div className={styles.inlineErrorHint}>Click to view full stack trace</div>
                </div>
              </div>
            ) : null
          }
        />
      </div>
    </div>
  )
}
