/*
 * SCR-27 옥션 상세·실시간 순위·응찰 [M15]. 실 API 전환(폴링).
 * 정본: GET /api/auctions/{id} (AuctionDetail) · POST /{id}/bids · POST /{id}/close.
 * 대상: 장치업체(응찰)·발주자. 좌 AI 자료 뷰어 + 우 봉인 순위·응찰.
 * ★ 봉인 입찰(서버 강제): 응답의 ranking 은 이미 마스킹됨 — 타사 금액/업체명 없음.
 *   화면은 서버가 준 priceMasked/price 만 렌더(클라이언트 언마스킹 없음). refetchInterval 5초.
 */
import { useEffect, useState } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next';
import { Button } from '../../components/ui/Button';
import { AiLabel } from '../../components/ui/Badge';
import { ErrorState, Skeleton } from '../../components/ui/States';
import { IconDocument, IconExpand, IconImage, IconPlus } from '../../components/ui/icons';
import {
  auctionApi,
  formatWon,
  type AuctionDetail,
  type MaterialKind,
  type RankRow,
} from './auctionApi';
import { errMessage, useToast } from './aucShared';
import './auction.css';

const REF_DESC: Record<MaterialKind, { label: string; title: string; desc: string; ai?: boolean }> = {
  layout: {
    label: '배치도',
    title: '배치도 (M2)',
    desc: '부스 위치·주변 통로·트렌치 좌표가 표시된 홀 배치도입니다.',
  },
  design: {
    label: '부스 설계안',
    title: '부스 설계안 (M3)',
    desc: '선택·병합된 최종 부스 설계 초안(3D/평면)입니다.',
  },
  boq: {
    label: '물량서(BOQ)',
    title: '물량서 (M4 · BOQ)',
    desc: '공종·자재·수량·규격이 정리된 시공 물량 산출서입니다.',
  },
  aiimage: {
    label: '예상 이미지',
    title: '예상 이미지 (M5)',
    desc: '나노바나나로 생성한 시공 후 예상 결과 이미지입니다.',
    ai: true,
  },
};

export function AuctionDetailPage() {
  const { auctionId = '' } = useParams();
  const navigate = useNavigate();
  const qc = useQueryClient();
  const { show, node: toast } = useToast();
  const [tab, setTab] = useState<MaterialKind>('layout');
  const [anon, setAnon] = useState(true);
  const [seconds, setSeconds] = useState(0);
  const [bidPrice, setBidPrice] = useState('');
  const [leadDays, setLeadDays] = useState('');

  const q = useQuery({
    queryKey: ['auction', auctionId],
    queryFn: () => auctionApi.detail(auctionId),
    enabled: !!auctionId,
    retry: false,
    refetchInterval: 5000,
  });
  const detail = q.data;

  // F035 물량서(BOQ) — 자료 탭이 boq 일 때만 서버 규칙 기반 산출 조회.
  const boqQ = useQuery({
    queryKey: ['auction', auctionId, 'boq'],
    queryFn: () => auctionApi.boq(auctionId),
    enabled: !!auctionId && tab === 'boq',
    retry: false,
  });

  // 카운트다운(로컬 tick) — deadline 기준. detail 갱신 시 재동기화.
  useEffect(() => {
    if (!detail?.deadline) return;
    const target = new Date(detail.deadline).getTime();
    const sync = () => setSeconds(Math.max(0, Math.floor((target - Date.now()) / 1000)));
    sync();
    const id = window.setInterval(sync, 1000);
    return () => window.clearInterval(id);
  }, [detail?.deadline]);

  // 자료 탭 초기값 = 존재하는 첫 자료
  useEffect(() => {
    if (detail && detail.materials.length && !detail.materials.includes(tab)) {
      setTab(detail.materials[0]);
    }
  }, [detail, tab]);

  const bidM = useMutation({
    mutationFn: () =>
      auctionApi.bid(auctionId, {
        total: Number(bidPrice),
        leadDays: leadDays ? Number(leadDays) : undefined,
      }),
    onSuccess: (r) => {
      show(`응찰 완료 — 현재 ${r.myRank ?? '-'}위 (v${r.version})`);
      setBidPrice('');
      qc.invalidateQueries({ queryKey: ['auction', auctionId] });
    },
    onError: (e) => show(errMessage(e)),
  });

  const closeM = useMutation({
    mutationFn: () => auctionApi.close(auctionId),
    onSuccess: () => {
      show('라운드를 마감했습니다. 봉인이 해제되어 견적 비교가 가능합니다.');
      qc.invalidateQueries({ queryKey: ['auction', auctionId] });
    },
    onError: (e) => show(errMessage(e)),
  });

  if (q.isLoading) {
    return (
      <div className="kx-page kx-auc">
        <Skeleton height={64} radius={12} />
        <div style={{ height: 16 }} />
        <Skeleton height={420} radius={16} />
      </div>
    );
  }
  if (q.isError || !detail) {
    return (
      <div className="kx-page kx-auc">
        <ErrorState message="옥션 상세를 불러오지 못했습니다." onRetry={() => q.refetch()} />
      </div>
    );
  }

  const active = REF_DESC[tab];
  const closed = detail.status !== '진행중';

  return (
    <div className="kx-page kx-auc">
      {/* 상단 히어로 — Nifty blog 상세 헤더(브레드크럼·제목·상태·메타) */}
      <header className="kx-detailview__hero">
        <nav className="kx-detailview__crumb" aria-label="경로">
          <button type="button" onClick={() => navigate('/auctions')}>
            공사 옥션
          </button>
          <span aria-hidden="true">/</span>
          <span className="kx-detailview__crumb-cur">{detail.title}</span>
        </nav>
        <div className="kx-detailview__title-row">
          {!closed && (
            <span className="kx-live">
              <span className="kx-live__dot" aria-hidden="true" />
              실시간
            </span>
          )}
          <h1 className="kx-detailview__title">{detail.title}</h1>
          <span
            className={`kx-detailview__badge ${
              closed ? 'kx-detailview__badge--info' : 'kx-detailview__badge--ok'
            }`}
          >
            {detail.status === '진행중' ? '활성 응찰 중' : detail.status}
          </span>
          <div className="kx-detailview__hero-aside">
            <div className="kx-aucd__metric">
              <span className="kx-aucd__metric-label">현재 최저가</span>
              <span className="kx-aucd__metric-value tnum">
                {detail.lowestPrice != null ? formatWon(detail.lowestPrice) : '—'}
              </span>
            </div>
          </div>
        </div>
        <div className="kx-detailview__meta">
          <span className="kx-detailview__meta-item">
            <span className="kx-detailview__meta-label">유형</span>
            <span className="kx-detailview__meta-value">{detail.type}</span>
          </span>
          <span className="kx-detailview__meta-item">
            <span className="kx-detailview__meta-label">라운드</span>
            <span className="kx-detailview__meta-value">{detail.round}</span>
          </span>
        </div>
      </header>

      <div className="kx-aucd__grid">
        {/* 좌 — AI 자료 뷰어 */}
        <section className="kx-viewer" aria-label="AI 설계 자료 뷰어">
          <div className="kx-viewer__tabs" role="tablist" aria-label="자료 종류">
            {detail.materials.map((kind) => (
              <button
                key={kind}
                role="tab"
                aria-selected={tab === kind}
                className={`kx-viewer__tab ${tab === kind ? 'is-active' : ''}`}
                onClick={() => setTab(kind)}
              >
                {REF_DESC[kind].label}
              </button>
            ))}
          </div>
          <div className="kx-viewer__stage">
            {tab === 'boq' ? (
              <BoqPanel query={boqQ} onRetry={() => boqQ.refetch()} />
            ) : (
              <div className="kx-viewer__placeholder">
                {tab === 'aiimage' ? <IconImage size={40} /> : <IconDocument size={40} />}
                <p className="kx-viewer__placeholder-title">{active.title}</p>
                <p className="kx-viewer__placeholder-desc">{active.desc}</p>
                {active.ai && <AiLabel>AI 생성 예상 이미지</AiLabel>}
              </div>
            )}
            {active.ai && <span className="kx-viewer__watermark">AI 생성 예상 이미지</span>}
            <div style={{ position: 'absolute', top: 12, right: 12 }}>
              <button
                type="button"
                className="kx-viewer__tab"
                style={{ color: 'rgba(255,255,255,0.8)', height: 'auto' }}
                onClick={() => show('전체화면 뷰어는 자료 스토리지 연동 후 제공됩니다.')}
                aria-label="전체화면"
              >
                <IconExpand size={18} />
              </button>
            </div>
          </div>
        </section>

        {/* 우 — 실시간 순위·응찰 */}
        <aside className="kx-rank" aria-label="실시간 순위">
          <div className="kx-rank__head">
            <h2>실시간 순위</h2>
            <button
              type="button"
              className="kx-toggle"
              aria-pressed={anon}
              onClick={() => setAnon((v) => !v)}
            >
              익명 순위
              <span className={`kx-toggle__track ${anon ? 'is-on' : ''}`}>
                <span className="kx-toggle__knob" />
              </span>
            </button>
          </div>

          <div className="kx-auc__gate kx-auc__gate--seal" style={{ margin: '0 16px' }}>
            {detail.sealed
              ? '봉인 입찰 — 마감 전 경쟁 견적 금액은 비공개, 최저가만 공개됩니다.'
              : '마감됨 — 발주자 견적 비교에서 전체가 공개됩니다.'}
          </div>

          <div className="kx-rank__list">
            {detail.ranking.length === 0 ? (
              <p className="kx-rank__note" style={{ padding: '8px 16px' }}>
                아직 응찰이 없습니다.
              </p>
            ) : (
              detail.ranking.map((r) => <RankRowItem key={r.rank} row={r} anon={anon} />)
            )}
          </div>

          <div className="kx-rank__foot">
            {!closed && (
              <div className="kx-countdown">
                <span className="kx-countdown__label">라운드 종료까지</span>
                <span className="kx-countdown__value">{fmtClock(seconds)}</span>
              </div>
            )}

            {detail.canBid ? (
              <>
                <div className="kx-grid-2" style={{ marginBottom: 8 }}>
                  <div className="kx-field">
                    <label className="kx-field__label" htmlFor="bid-price">
                      응찰 총액(부가세 별도)
                    </label>
                    <input
                      id="bid-price"
                      className="kx-input"
                      type="number"
                      min={1}
                      value={bidPrice}
                      placeholder="예: 8400000"
                      onChange={(e) => setBidPrice(e.target.value)}
                    />
                  </div>
                  <div className="kx-field">
                    <label className="kx-field__label" htmlFor="bid-lead">
                      납기(일)
                    </label>
                    <input
                      id="bid-lead"
                      className="kx-input"
                      type="number"
                      min={0}
                      value={leadDays}
                      placeholder="예: 12"
                      onChange={(e) => setLeadDays(e.target.value)}
                    />
                  </div>
                </div>
                <Button
                  block
                  leadingIcon={<IconPlus size={16} />}
                  onClick={() => {
                    if (!bidPrice || Number(bidPrice) <= 0) return show('응찰 금액을 입력해 주세요.');
                    bidM.mutate();
                  }}
                  disabled={bidM.isPending}
                >
                  {bidM.isPending ? '제출 중…' : '견적서 제출 · 재응찰'}
                </Button>
                <p className="kx-rank__note">
                  재응찰 시 이전 응찰 정보는 자동 대체됩니다(버전 증가). 킨텍스 등록업체만 응찰할 수
                  있습니다.
                </p>
              </>
            ) : (
              <p className="kx-rank__note">
                {closed
                  ? '마감된 옥션입니다. 응찰이 종료되었습니다.'
                  : '응찰 권한이 없습니다 — 킨텍스 등록 장치업체(초대 대상)만 응찰할 수 있습니다.'}
              </p>
            )}

            {detail.canViewAward && (
              <Button
                variant="secondary"
                block
                style={{ marginTop: 8 }}
                onClick={() => navigate(`/auctions/${auctionId}/award`)}
              >
                견적 비교·낙찰로 이동
              </Button>
            )}
            {!closed && detail.canViewAward === false && isOrdererHint(detail) && (
              <Button
                variant="ghost"
                block
                style={{ marginTop: 8 }}
                onClick={() => closeM.mutate()}
                disabled={closeM.isPending}
              >
                {closeM.isPending ? '마감 중…' : '라운드 마감(발주자)'}
              </Button>
            )}
          </div>
        </aside>
      </div>
      {toast}
    </div>
  );
}

/** 발주자이면서 아직 마감 전이라 close 버튼을 노출할지 힌트. canBid=false + !canViewAward + 응찰 불가 상태에서 노출. */
function isOrdererHint(d: AuctionDetail): boolean {
  // 발주자 판단은 서버가 canViewAward(마감 후)로만 노출하므로, 마감 전에는 close 버튼을 항상 시도 가능하게 둔다
  // (권한 없으면 서버가 403 → 토스트). 응찰 가능한 업체에는 노출하지 않는다.
  return !d.canBid;
}

function RankRowItem({ row, anon }: { row: RankRow; anon: boolean }) {
  const cls = row.isMe ? 'kx-rank__row--me' : row.isLowest ? 'kx-rank__row--lowest' : '';
  const name = row.isMe ? '나의 응찰 (ME)' : anon ? row.alias : `(주)협력사 ${row.rank}`;
  return (
    <div className={`kx-rank__row ${cls}`}>
      <span className="kx-rank__badge">{row.rank}</span>
      <div className="kx-rank__main">
        <p className="kx-rank__alias">{name}</p>
        {!row.priceMasked && row.price != null ? (
          <p className="kx-rank__price tnum">{formatWon(row.price)}</p>
        ) : (
          <p className="kx-rank__price--masked" title="봉인 입찰 — 마감 후 공개">
            비공개 · 봉인
          </p>
        )}
      </div>
      {row.isLowest && <span className="kx-rank__tag">최저가</span>}
      {row.isMe && (
        <span
          className="kx-rank__tag"
          style={{ background: 'var(--color-ai-surface)', color: 'var(--color-ai-accent)' }}
        >
          나의 순위
        </span>
      )}
    </div>
  );
}

function fmtClock(total: number): string {
  const h = Math.floor(total / 3600);
  const m = Math.floor((total % 3600) / 60);
  const s = total % 60;
  const p = (n: number) => n.toString().padStart(2, '0');
  return `${p(h)}:${p(m)}:${p(s)}`;
}

/** F035 물량서(BOQ) 표 — 서버 규칙 기반 산출값(공종·품명·단위·수량·근거). 금액은 응찰 견적서에서 산정. */
function BoqPanel({
  query,
  onRetry,
}: {
  query: ReturnType<typeof useQuery<import('./auctionApi').BoqResult>>;
  onRetry: () => void;
}) {
  const { t } = useTranslation();
  if (query.isLoading) {
    return (
      <div className="kx-boq">
        <Skeleton height={28} radius={8} />
        <div style={{ height: 8 }} />
        <Skeleton height={180} radius={8} />
      </div>
    );
  }
  if (query.isError || !query.data) {
    return (
      <div className="kx-boq">
        <ErrorState message={t('auction.boq.error')} onRetry={onRetry} />
      </div>
    );
  }
  const boq = query.data;
  return (
    <div className="kx-boq">
      <div className="kx-boq__head">
        <h3 className="kx-boq__title">{t('auction.boq.title')}</h3>
        <span className="kx-boq__scope">
          {boq.scope === 'booth'
            ? t('auction.boq.scopeBooth', { label: boq.scopeLabel })
            : t('auction.boq.scopeEvent')}
          {' · '}
          {t('auction.boq.summary', { count: boq.boothCount, area: boq.totalAreaM2.toLocaleString() })}
        </span>
      </div>
      {boq.lines.length === 0 ? (
        <p className="kx-boq__note">{boq.note}</p>
      ) : (
        <>
          <div className="kx-boq__scroll">
            <table className="kx-table">
              <thead>
                <tr>
                  <th>{t('auction.boq.colSeq')}</th>
                  <th>{t('auction.boq.colTrade')}</th>
                  <th>{t('auction.boq.colItem')}</th>
                  <th className="kx-num">{t('auction.boq.colQty')}</th>
                  <th>{t('auction.boq.colUnit')}</th>
                  <th>{t('auction.boq.colBasis')}</th>
                </tr>
              </thead>
              <tbody>
                {boq.lines.map((l) => (
                  <tr key={l.seq}>
                    <td className="tnum">{l.seq}</td>
                    <td>
                      <span className="kx-boq__trade">{l.trade}</span>
                    </td>
                    <td>{l.item}</td>
                    <td className="kx-num tnum">{l.qty.toLocaleString()}</td>
                    <td>{l.unit}</td>
                    <td className="kx-boq__basis">{l.basis}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
          <p className="kx-boq__note">{boq.note}</p>
        </>
      )}
    </div>
  );
}
