"use client";

import { useState, type ReactNode } from "react";
import { cx } from "../../utils";
import { FoxPageHeader } from "../fox-page-header";
import type { FoxBreadcrumbItem } from "../fox-breadcrumb";
import { FoxTable } from "../fox-table";
import { FoxTableRow } from "../fox-table-row";
import { FoxTableCell } from "../fox-table-cell";
import type { FoxTableCellAlign } from "../fox-table-cell";
import { FoxPagination } from "../fox-pagination";
import { FoxListCount, FoxListToolbar } from "../fox-list-toolbar";
import { FoxListSearch } from "../fox-list-search";
import type { FoxSelectItem } from "../fox-select";

/** 열 하나의 정의. `render`가 있으면 그 결과가 셀 내용이 된다. */
export interface FoxListColumn<T> {
  /** 열 식별자. `render`가 없으면 `row[key]`를 그대로 그린다. */
  key: string;
  header: ReactNode;
  /** 셀을 직접 그린다 — 배지·버튼 무엇이든 넣을 수 있다. */
  render?: (row: T, index: number) => ReactNode;
  width?: string | number;
  align?: FoxTableCellAlign;
  /** 참이면 그 열의 본문 글자가 진해진다(시안의 강조 열). */
  emphasis?: boolean;
}

/**
 * 목록 상태의 변경분. 컨테이너는 **바뀐 것만** 담아 넘긴다 — 호출부가 기존 값과 합쳐
 * 쓰라는 뜻이다. 화면마다 필요한 정렬·필터 키가 달라 열려 있는 모양이다.
 */
export interface FoxListQueryPatch {
  page?: number;
  keyword?: string;
  searchField?: string;
  [key: string]: unknown;
}

export interface FoxListContainerProps<T> {
  // ── 머리말 ────────────────────────────────────────────────────────────────
  title?: ReactNode;
  breadcrumb?: FoxBreadcrumbItem[];
  /** 제목 아래 한 줄 설명 — `FoxPageHeader`로 그대로 간다. */
  description?: ReactNode;
  headerActions?: ReactNode;
  /**
   * 머리말과 목록 사이. 시안에서 이 자리에 오는 것은 `FoxTab`이다 — 목록 전체를 갈아 끼우는
   * 전환이라 도구 줄(정렬·검색)보다 위에 선다.
   */
  tabs?: ReactNode;

  // ── 표 ────────────────────────────────────────────────────────────────────
  columns: FoxListColumn<T>[];
  rows: T[];
  /** 행의 안정적인 키. 인덱스를 쓰면 정렬·페이지 이동에서 어긋난다. */
  rowKey: (row: T, index: number) => string;
  caption?: string;
  /** 행이 없을 때 표 안에 보여줄 말. */
  emptyMessage?: ReactNode;
  /** 주면 행 전체가 눌린다 — 관리 열 없이 행을 눌러 상세를 여는 시안에 쓴다. */
  onRowSelect?: (row: T, index: number) => void;

  // ── 도구 줄 ───────────────────────────────────────────────────────────────
  /** 주면 "총 N건"이 나온다. 없으면 그 자리를 비운다. */
  totalCount?: number;
  toolbarLeading?: ReactNode;
  sorts?: ReactNode;
  toolbarActions?: ReactNode;
  filter?: ReactNode;

  /** 검색 대상 목록. 주면 검색 상자가 나온다. 대상이 하나뿐이면 빈 배열로 두면 된다. */
  searchFields?: FoxSelectItem[];
  searchField?: string;
  keyword?: string;
  searchPlaceholder?: string;
  /** 검색 상자를 아예 숨긴다. */
  searchHidden?: boolean;

  // ── 페이지 ────────────────────────────────────────────────────────────────
  page?: number;
  totalPages?: number;

  // ── 이벤트 ────────────────────────────────────────────────────────────────
  /**
   * 주면 페이지 이동이 **링크**가 된다 — 목록이 Server Component로 남고 새로고침·뒤로가기·
   * URL 공유가 그대로 동작한다. 이 저장소의 목록 화면들이 쓰는 방식이다.
   */
  buildHref?: (patch: FoxListQueryPatch) => string;
  /** `buildHref`가 없을 때(모달 안 목록 등) 쓰는 콜백. 둘 다 주면 링크가 이긴다. */
  onQueryChange?: (patch: FoxListQueryPatch) => void;

  hidden?: boolean;
  className?: string;
}

/**
 * @fox 목록 화면 뼈대 — 시안: 관리자페이지(QsFVFFUKGH68xAPVkF3SJ9) container (3019:8608)
 *
 * 머리말 · 도구 줄 · 표 · 페이지네이션을 한 벌로 묶는다. **데이터를 가져오지도, 상태를 갖지도
 * 않는다** — 받은 것을 그리고 바뀐 것을 알릴 뿐이라 어떤 목록에도 그대로 쓸 수 있다.
 *
 * 표는 `columns` 정의로 그린다. `render`가 ReactNode를 돌려주므로 셀 안에 배지든 버튼 묶음이든
 * 들어간다(시안이 그렇다) — 값의 형식을 컨테이너가 알 필요가 없다.
 *
 * 이벤트는 두 갈래다. `buildHref`를 주면 링크로 그려 URL이 상태가 되고, `onQueryChange`만
 * 주면 콜백으로 알린다. FoxPagination이 이미 같은 방식이라 그 관례를 따랐다.
 *
 * ⚠️ 스타일은 이 파일이 import하지 않는다 — 호스트 앱이 `@use "@fox/styles/components"`
 * (또는 개별 파티셜)로 한 번 불러와야 한다.
 */
export function FoxListContainer<T>({
  title,
  breadcrumb,
  description,
  headerActions,
  tabs,
  columns,
  rows,
  rowKey,
  caption,
  emptyMessage = "조회된 내용이 없습니다.",
  onRowSelect,
  totalCount,
  toolbarLeading,
  sorts,
  toolbarActions,
  filter,
  searchFields,
  searchField,
  keyword,
  searchPlaceholder,
  searchHidden = false,
  page = 1,
  totalPages = 1,
  buildHref,
  onQueryChange,
  hidden = false,
  className,
}: FoxListContainerProps<T>) {
  const applied = { keyword: keyword ?? "", field: searchField };
  const [draft, setDraft] = useState(applied);
  const [lastApplied, setLastApplied] = useState(applied);

  if (
    lastApplied.keyword !== applied.keyword ||
    lastApplied.field !== applied.field
  ) {
    setLastApplied(applied);
    setDraft(applied);
  }

  if (hidden) {
    return null;
  }

  const hasToolbar =
    totalCount !== undefined ||
    toolbarLeading !== undefined ||
    sorts !== undefined ||
    toolbarActions !== undefined ||
    filter !== undefined ||
    !searchHidden;

  return (
    <div className={cx("fox-list-container", className)}>
      {(title !== undefined || breadcrumb !== undefined) && (
        <FoxPageHeader
          title={title}
          breadcrumb={breadcrumb}
          description={description}
          actions={headerActions}
        />
      )}

      {tabs}

      <section className="fox-list-container__section">
        {hasToolbar && (
          <FoxListToolbar
            count={
              totalCount !== undefined ? (
                <FoxListCount total={totalCount} />
              ) : undefined
            }
            leading={toolbarLeading}
            sorts={sorts}
            search={
              searchHidden ? undefined : (
                <FoxListSearch
                  fields={searchFields}
                  field={draft.field}
                  onFieldChange={(next) =>
                    setDraft((current) => ({ ...current, field: next }))
                  }
                  keyword={draft.keyword}
                  onKeywordChange={(next) =>
                    setDraft((current) => ({ ...current, keyword: next }))
                  }
                  placeholder={searchPlaceholder}
                  onSearch={(nextKeyword, nextField) =>
                    onQueryChange?.({
                      keyword: nextKeyword,
                      searchField: nextField,
                      // 검색 결과는 항상 첫 장부터 본다 — 남아 있던 페이지 번호를 지운다.
                      page: 1,
                    })
                  }
                />
              )
            }
            actions={toolbarActions}
            filter={filter}
          />
        )}

        {/* 열이 많으면 표가 화면보다 넓어진다. 눌러 담지 않고 이 래퍼가 가로로 스크롤한다. */}
        <div className="fox-list-container__table">
        {/* `thead`/`tbody`로 감싸지 않는다 — FoxTable이 스스로 만들고, 머리행은 `head`만 보고
            제자리로 보낸다. 감싸면 표 안에 표 구조가 이중으로 생긴다. */}
        <FoxTable type="list" caption={caption}>
          {/* 머리칸은 열 정렬을 받지 않는다 — 상단 머리행은 늘 가운데(디자인팀 확정). */}
          <FoxTableRow head>
            {columns.map((column) => (
              <FoxTableCell key={column.key} head width={column.width}>
                {column.header}
              </FoxTableCell>
            ))}
          </FoxTableRow>

          {rows.length === 0 ? (
            <FoxTableRow>
              <FoxTableCell colSpan={columns.length} align="center">
                {emptyMessage}
              </FoxTableCell>
            </FoxTableRow>
          ) : (
            rows.map((row, index) => (
              <FoxTableRow
                key={rowKey(row, index)}
                onSelect={
                  onRowSelect ? () => onRowSelect(row, index) : undefined
                }
              >
                {columns.map((column) => (
                  <FoxTableCell
                    key={column.key}
                    align={column.align}
                    emphasis={column.emphasis}
                    label={
                      typeof column.header === "string"
                        ? column.header
                        : undefined
                    }
                  >
                    {column.render
                      ? column.render(row, index)
                      : String(
                          (row as Record<string, unknown>)[column.key] ?? ""
                        )}
                  </FoxTableCell>
                ))}
              </FoxTableRow>
            ))
          )}
          </FoxTable>
        </div>

        {totalPages > 1 && (
          <FoxPagination
            currentPage={page}
            totalPages={totalPages}
            buildHref={buildHref ? (next) => buildHref({ page: next }) : undefined}
            onPageChange={
              buildHref ? undefined : (next) => onQueryChange?.({ page: next })
            }
          />
        )}
      </section>
    </div>
  );
}
