import { useState, useEffect, useCallback, useMemo } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import type { ServiceCatalog } from '../../types/apihub';
import type { ApiDetailInfo } from '../../types/service';
import { getCatalog, getServiceCatalog, getApiHubApiDetail } from '../../services/apiHubService';
import { getSystemConfig } from '../../services/configService';
import { createKeyRequest } from '../../services/apiKeyService';

const COMMON_SAMPLE_CODE_KEY = 'COMMON_SAMPLE_CODE';

const METHOD_COLORS_LARGE: Record<string, string> = {
  GET: 'bg-green-500',
  POST: 'bg-blue-500',
  PUT: 'bg-amber-500',
  PATCH: 'bg-amber-500',
  DELETE: 'bg-red-500',
};

const ApiHubApiDetailPage = () => {
  const { serviceId, apiId } = useParams<{ serviceId: string; apiId: string }>();
  const navigate = useNavigate();
  const [detail, setDetail] = useState<ApiDetailInfo | null>(null);
  const [service, setService] = useState<ServiceCatalog | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [paramInputs, setParamInputs] = useState<Record<string, string>>({});
  const [generatedUrl, setGeneratedUrl] = useState<string | null>(null);
  const [urlCopied, setUrlCopied] = useState(false);
  const [validationErrors, setValidationErrors] = useState<Record<string, boolean>>({});
  const [commonSampleCode, setCommonSampleCode] = useState<string | null>(null);
  const [urlGenOpen, setUrlGenOpen] = useState(false);

  // 신청 모달 상태
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [modalKeyName, setModalKeyName] = useState('');
  const [modalPurpose, setModalPurpose] = useState('');
  const [modalServiceIp, setModalServiceIp] = useState('');
  const [modalServicePurpose, setModalServicePurpose] = useState('');
  const [modalDailyRequestEstimate, setModalDailyRequestEstimate] = useState('');
  const [modalUsagePeriodMode, setModalUsagePeriodMode] = useState<'preset' | 'custom'>('preset');
  const [modalIsPermanent, setModalIsPermanent] = useState(false);
  const [modalUsageFromDate, setModalUsageFromDate] = useState('');
  const [modalUsageToDate, setModalUsageToDate] = useState('');
  const [modalIsSubmitting, setModalIsSubmitting] = useState(false);
  const [modalError, setModalError] = useState<string | null>(null);
  const [modalSuccess, setModalSuccess] = useState(false);
  const [modalSelectedApiIds, setModalSelectedApiIds] = useState<Set<number>>(new Set());
  const [modalCatalog, setModalCatalog] = useState<ServiceCatalog[]>([]);
  const [modalExpandedDomains, setModalExpandedDomains] = useState<Set<string>>(new Set());
  const [modalApiSearch, setModalApiSearch] = useState('');

  const fetchData = useCallback(async () => {
    if (!serviceId || !apiId) return;
    try {
      const [serviceRes, detailRes, sampleCodeRes] = await Promise.all([
        getServiceCatalog(Number(serviceId)),
        getApiHubApiDetail(Number(serviceId), Number(apiId)),
        getSystemConfig(COMMON_SAMPLE_CODE_KEY),
      ]);
      if (serviceRes.success && serviceRes.data) {
        setService(serviceRes.data);
      }
      if (detailRes.success && detailRes.data) {
        setDetail(detailRes.data);
      } else {
        setError('API 정보를 불러오지 못했습니다');
      }
      if (sampleCodeRes.success && sampleCodeRes.data?.configValue) {
        setCommonSampleCode(sampleCodeRes.data.configValue);
      }
    } catch {
      setError('API 정보를 불러오는 중 오류가 발생했습니다');
    } finally {
      setIsLoading(false);
    }
  }, [serviceId, apiId]);

  useEffect(() => {
    setParamInputs({});
    setGeneratedUrl(null);
    setUrlCopied(false);
    setValidationErrors({});
    setIsLoading(true);
    setError(null);
    fetchData();
  }, [fetchData]);

  const urlInputParams = useMemo(() =>
    detail?.requestParams.filter((p) => p.paramName.toUpperCase() !== 'URL') ?? [],
    [detail?.requestParams]
  );

  if (isLoading) {
    return (
      <div className="flex items-center justify-center h-64">
        <div className="text-gray-500 dark:text-gray-400">로딩 중...</div>
      </div>
    );
  }

  if (error || !detail) {
    return (
      <div>
        <button
          onClick={() => navigate(`/api-hub/services/${serviceId}`)}
          className="text-sm text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300 mb-4 inline-block"
        >
          ← 서비스로
        </button>
        <div className="text-center py-20 text-gray-500 dark:text-gray-400">
          {error ?? 'API를 찾을 수 없습니다'}
        </div>
      </div>
    );
  }

  const api = detail.api;
  const spec = detail.spec;
  const domainLabel = api.apiDomain ? api.apiDomain.toUpperCase() : '기타';

  const handleGenerateUrl = () => {
    const errors: Record<string, boolean> = {};
    for (const p of urlInputParams) {
      if (p.required && !paramInputs[p.paramName]?.trim()) {
        errors[p.paramName] = true;
      }
    }
    setValidationErrors(errors);
    if (Object.keys(errors).length > 0) return;

    const base = spec?.sampleUrl || (service?.serviceUrl ? `${service.serviceUrl}${api.apiPath}` : api.apiPath);
    const queryParts: string[] = [];
    for (const p of urlInputParams) {
      const val = paramInputs[p.paramName];
      if (val) {
        const type = (p.inputType || 'TEXT').toUpperCase();
        let formatted = val;
        if (type === 'DATE' || type === 'DATETIME') {
          formatted = new Date(val).toISOString();
        }
        queryParts.push(`${p.paramName}=${formatted}`);
      }
    }
    const url = queryParts.length > 0
      ? `${base}${base.includes('?') ? '&' : '?'}${queryParts.join('&')}`
      : base;
    setGeneratedUrl(url);
    setUrlCopied(false);
  };

  const handleCopyGeneratedUrl = () => {
    if (generatedUrl) {
      navigator.clipboard.writeText(generatedUrl);
      setUrlCopied(true);
      setTimeout(() => setUrlCopied(false), 2000);
    }
  };

  const handleOpenModal = async () => {
    setModalKeyName('');
    setModalPurpose('');
    setModalServiceIp('');
    setModalServicePurpose('');
    setModalDailyRequestEstimate('');
    setModalUsagePeriodMode('preset');
    setModalIsPermanent(false);
    setModalUsageFromDate('');
    setModalUsageToDate('');
    setModalError(null);
    setModalSuccess(false);
    setModalApiSearch('');
    if (detail) {
      setModalSelectedApiIds(new Set([detail.api.apiId]));
      // 현재 API의 도메인을 펼침
      const currentDomain = detail.api.apiDomain ?? '';
      setModalExpandedDomains(new Set([currentDomain.toUpperCase()]));
    }
    setIsModalOpen(true);
    if (modalCatalog.length === 0) {
      const res = await getCatalog();
      if (res.data) setModalCatalog(res.data);
    }
  };

  const handleCloseModal = () => {
    setIsModalOpen(false);
  };

  const handleModalPresetPeriod = (months: number) => {
    const from = new Date();
    const to = new Date();
    to.setMonth(to.getMonth() + months);
    setModalUsageFromDate(from.toISOString().split('T')[0]);
    setModalUsageToDate(to.toISOString().split('T')[0]);
    setModalUsagePeriodMode('preset');
    setModalIsPermanent(false);
  };

  const handleModalPermanent = () => {
    setModalIsPermanent(true);
    setModalUsageFromDate('');
    setModalUsageToDate('');
  };

  const handleModalSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (modalSelectedApiIds.size === 0) {
      setModalError('최소 하나의 API를 선택해주세요.');
      return;
    }
    if (!modalIsPermanent && (!modalUsageFromDate || !modalUsageToDate)) {
      setModalError('사용 기간을 설정해주세요.');
      return;
    }
    setModalError(null);
    setModalIsSubmitting(true);
    try {
      const res = await createKeyRequest({
        keyName: modalKeyName,
        purpose: modalPurpose || undefined,
        requestedApiIds: Array.from(modalSelectedApiIds),
        serviceIp: modalServiceIp || undefined,
        servicePurpose: modalServicePurpose || undefined,
        dailyRequestEstimate: modalDailyRequestEstimate ? Number(modalDailyRequestEstimate) : undefined,
        usageFromDate: modalIsPermanent ? undefined : modalUsageFromDate,
        usageToDate: modalIsPermanent ? undefined : modalUsageToDate,
      });
      if (res.success) {
        setModalSuccess(true);
        setTimeout(() => {
          setIsModalOpen(false);
        }, 2000);
      } else {
        setModalError(res.message || 'API Key 신청에 실패했습니다.');
      }
    } catch {
      setModalError('API Key 신청에 실패했습니다.');
    } finally {
      setModalIsSubmitting(false);
    }
  };

  return (
    <div className="max-w-7xl mx-auto">
      {/* Breadcrumb */}
      <nav className="flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400 mb-4">
        <button
          onClick={() => navigate('/api-hub')}
          className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
        >
          API HUB
        </button>
        <span>/</span>
        <button
          onClick={() => navigate(`/api-hub/domains/${encodeURIComponent(domainLabel)}`)}
          className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
        >
          {domainLabel}
        </button>
        <span>/</span>
        <span className="text-gray-900 dark:text-gray-100 font-medium truncate max-w-xs">{api.apiName}</span>
      </nav>

      {/* Header Card */}
      <div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6 mb-6 border border-gray-100 dark:border-gray-700">
        <div className="flex items-center justify-between gap-4">
          <div className="flex items-center gap-4">
            <span
              className={`px-3 py-1.5 rounded text-sm font-bold uppercase text-white shrink-0 ${METHOD_COLORS_LARGE[api.apiMethod] ?? 'bg-gray-500'}`}
            >
              {api.apiMethod}
            </span>
            <h1 className="text-xl font-bold text-gray-900 dark:text-gray-100">{api.apiName}</h1>
          </div>
          <button
            onClick={handleOpenModal}
            className="shrink-0 px-4 py-2 rounded-lg bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium transition-colors"
          >
            API 사용 신청
          </button>
        </div>
      </div>

      <div className="space-y-6">

        {/* 기본 정보 */}
        {api.description && (
          <div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6 border border-gray-100 dark:border-gray-700">
            <h2 className="text-base font-semibold text-gray-900 dark:text-gray-100 mb-4">기본 정보</h2>
            <p className="text-sm text-gray-700 dark:text-gray-300 leading-relaxed whitespace-pre-wrap">{api.description}</p>
          </div>
        )}

        {/* 샘플 URL */}
        {spec?.sampleUrl && (
          <div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6 border border-gray-100 dark:border-gray-700">
            <h2 className="text-base font-semibold text-gray-900 dark:text-gray-100 mb-3">샘플 URL</h2>
            <a
              href={spec.sampleUrl}
              target="_blank"
              rel="noopener noreferrer"
              className="text-sm text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300 break-all underline underline-offset-2 font-mono"
            >
              {spec.sampleUrl}
            </a>
          </div>
        )}

        {/* 요청 URL 생성 (아코디언) */}
        <div className="bg-white dark:bg-gray-800 rounded-lg shadow border border-gray-100 dark:border-gray-700">
          <button
            type="button"
            onClick={() => setUrlGenOpen((v) => !v)}
            className="w-full flex items-center justify-between px-6 py-4 text-left"
          >
            <h2 className="text-base font-semibold text-gray-900 dark:text-gray-100">요청 URL 생성</h2>
            <svg
              className={`w-5 h-5 text-gray-500 dark:text-gray-400 transition-transform duration-200 ${urlGenOpen ? 'rotate-180' : ''}`}
              fill="none"
              viewBox="0 0 24 24"
              stroke="currentColor"
              strokeWidth={2}
            >
              <path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" />
            </svg>
          </button>

          {urlGenOpen && (
            <div className="px-6 pb-6 border-t border-gray-100 dark:border-gray-700 pt-4">
              {/* URL 생성 폼 */}
              {urlInputParams.length > 0 && (
                <div className="mb-4">
                  <div className="space-y-3 mb-4">
                    {urlInputParams.map((p) => {
                      const hasError = validationErrors[p.paramName];
                      const inputCls = `flex-1 border ${hasError ? 'border-red-400 dark:border-red-500' : 'border-gray-300 dark:border-gray-600'} bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-1.5 text-sm focus:ring-1 focus:ring-blue-500 focus:outline-none`;
                      const type = (p.inputType || 'TEXT').toUpperCase();

                      return (
                        <div key={p.paramName}>
                          <div className="flex items-center gap-3">
                            <label className="w-36 shrink-0 text-sm font-medium text-gray-500 dark:text-gray-400">
                              {p.paramName}
                              {p.required && <span className="text-red-500 ml-0.5">*</span>}
                            </label>
                            {type === 'DATE' || type === 'DATETIME' ? (
                              <input
                                type={type === 'DATETIME' ? 'datetime-local' : 'date'}
                                value={paramInputs[p.paramName] || ''}
                                onChange={(e) => {
                                  setParamInputs((prev) => ({ ...prev, [p.paramName]: e.target.value }));
                                  if (hasError) setValidationErrors((prev) => ({ ...prev, [p.paramName]: false }));
                                }}
                                className={inputCls}
                              />
                            ) : type === 'NUMBER' ? (
                              <input
                                type="number"
                                value={paramInputs[p.paramName] || ''}
                                onChange={(e) => {
                                  setParamInputs((prev) => ({ ...prev, [p.paramName]: e.target.value }));
                                  if (hasError) setValidationErrors((prev) => ({ ...prev, [p.paramName]: false }));
                                }}
                                placeholder={p.paramMeaning || p.paramName}
                                className={inputCls}
                              />
                            ) : (
                              <input
                                type="text"
                                value={paramInputs[p.paramName] || ''}
                                onChange={(e) => {
                                  setParamInputs((prev) => ({ ...prev, [p.paramName]: e.target.value }));
                                  if (hasError) setValidationErrors((prev) => ({ ...prev, [p.paramName]: false }));
                                }}
                                placeholder={p.paramMeaning || p.paramName}
                                className={inputCls}
                              />
                            )}
                          </div>
                          {hasError && (
                            <p className="ml-[9.75rem] mt-1 text-xs text-red-500">{p.paramName}은(는) 필수입니다</p>
                          )}
                        </div>
                      );
                    })}
                  </div>
                  <button
                    onClick={handleGenerateUrl}
                    className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg text-sm font-medium transition-colors"
                  >
                    URL 생성
                  </button>
                </div>
              )}

              {/* 생성된 URL */}
              {generatedUrl && (
                <div className="mb-4">
                  <p className="text-xs font-medium text-gray-500 dark:text-gray-400 mb-1.5">생성된 요청 URL</p>
                  <div className="flex items-center p-3 bg-gray-50 dark:bg-gray-700 rounded-lg">
                    <span
                      className={`px-2 py-1 rounded text-xs font-bold uppercase text-white shrink-0 mr-3 ${METHOD_COLORS_LARGE[api.apiMethod] ?? 'bg-gray-500'}`}
                    >
                      {api.apiMethod}
                    </span>
                    <span className="font-mono text-sm text-gray-700 dark:text-gray-300 break-all flex-1">
                      {generatedUrl}
                    </span>
                    <button
                      onClick={handleCopyGeneratedUrl}
                      className="ml-2 px-2 py-0.5 text-xs bg-gray-200 dark:bg-gray-600 text-gray-600 dark:text-gray-300 rounded hover:bg-gray-300 dark:hover:bg-gray-500 transition-colors"
                    >
                      {urlCopied ? '복사됨' : '복사'}
                    </button>
                  </div>
                </div>
              )}

              {/* 샘플 코드 */}
              {commonSampleCode && (
                <div>
                  <p className="text-xs font-medium text-gray-500 dark:text-gray-400 mb-1.5">샘플 코드</p>
                  <pre className="bg-gray-900 text-green-400 text-sm font-mono p-4 rounded-lg overflow-x-auto">
                    {commonSampleCode}
                  </pre>
                </div>
              )}

              {urlInputParams.length === 0 && !commonSampleCode && (
                <p className="text-sm text-gray-400 dark:text-gray-500">요청인자가 등록되지 않았습니다</p>
              )}
            </div>
          )}
        </div>

        {/* 요청인자 */}
        {detail.requestParams.length > 0 && (
          <div className="bg-white dark:bg-gray-800 rounded-lg shadow border border-gray-100 dark:border-gray-700">
            <div className="px-6 py-4 border-b border-gray-100 dark:border-gray-700">
              <h2 className="text-base font-semibold text-gray-900 dark:text-gray-100">요청인자</h2>
            </div>
            <div className="overflow-x-auto">
              <table className="w-full text-sm">
                <thead className="bg-gray-50 dark:bg-gray-700">
                  <tr>
                    <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">인자명</th>
                    <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">의미</th>
                    <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">설명</th>
                  </tr>
                </thead>
                <tbody className="divide-y divide-gray-200 dark:divide-gray-700">
                  {detail.requestParams.map((param) => (
                    <tr key={param.paramId} className="hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
                      <td className="px-4 py-3 font-mono text-xs text-gray-900 dark:text-gray-100 font-medium">
                        {param.paramName}
                        {param.required && <span className="text-red-500 ml-0.5">*</span>}
                      </td>
                      <td className="px-4 py-3 text-gray-700 dark:text-gray-300">
                        {param.paramMeaning ?? <span className="text-gray-400 dark:text-gray-500">-</span>}
                      </td>
                      <td className="px-4 py-3 text-gray-600 dark:text-gray-400 max-w-xs">
                        {param.paramDescription ?? <span className="text-gray-400 dark:text-gray-500">-</span>}
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        )}

        {/* 출력결과 */}
        {detail.responseParams.length > 0 && (
          <div className="bg-white dark:bg-gray-800 rounded-lg shadow border border-gray-100 dark:border-gray-700">
            <div className="px-6 py-4 border-b border-gray-100 dark:border-gray-700">
              <h2 className="text-base font-semibold text-gray-900 dark:text-gray-100">출력결과</h2>
            </div>
            <div className="overflow-x-auto">
              <table className="w-full text-sm">
                <thead className="bg-gray-50 dark:bg-gray-700">
                  <tr>
                    <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase w-1/4">변수명</th>
                    <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase w-1/4">의미(단위)</th>
                    <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase w-1/4">변수명</th>
                    <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase w-1/4">의미(단위)</th>
                  </tr>
                </thead>
                <tbody className="divide-y divide-gray-200 dark:divide-gray-700">
                  {Array.from({ length: Math.ceil(detail.responseParams.length / 2) }, (_, rowIdx) => {
                    const left = detail.responseParams[rowIdx * 2];
                    const right = detail.responseParams[rowIdx * 2 + 1];
                    return (
                      <tr key={rowIdx} className="hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
                        <td className="px-4 py-3 font-mono text-xs text-gray-900 dark:text-gray-100 font-medium">
                          {left.paramName}
                        </td>
                        <td className="px-4 py-3 text-gray-700 dark:text-gray-300">
                          {left.paramMeaning ?? <span className="text-gray-400 dark:text-gray-500">-</span>}
                        </td>
                        {right ? (
                          <>
                            <td className="px-4 py-3 font-mono text-xs text-gray-900 dark:text-gray-100 font-medium">
                              {right.paramName}
                            </td>
                            <td className="px-4 py-3 text-gray-700 dark:text-gray-300">
                              {right.paramMeaning ?? <span className="text-gray-400 dark:text-gray-500">-</span>}
                            </td>
                          </>
                        ) : (
                          <>
                            <td className="px-4 py-3" />
                            <td className="px-4 py-3" />
                          </>
                        )}
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          </div>
        )}

        {/* 참고자료 */}
        {spec?.referenceUrl && (
          <div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6 border border-gray-100 dark:border-gray-700">
            <h2 className="text-base font-semibold text-gray-900 dark:text-gray-100 mb-3">참고자료</h2>
            <a
              href={spec.referenceUrl}
              target="_blank"
              rel="noopener noreferrer"
              className="text-sm text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300 break-all underline underline-offset-2"
            >
              {spec.referenceUrl}
            </a>
          </div>
        )}

        {/* 비고 */}
        {spec?.note && (
          <div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6 border border-gray-100 dark:border-gray-700">
            <h2 className="text-base font-semibold text-gray-900 dark:text-gray-100 mb-3">비고</h2>
            <p className="text-sm text-gray-700 dark:text-gray-300 leading-relaxed whitespace-pre-wrap">
              {spec.note}
            </p>
          </div>
        )}
      </div>

      {/* API 사용 신청 모달 */}
      {isModalOpen && (
        <div
          className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4"
          onClick={(e) => { if (e.target === e.currentTarget) handleCloseModal(); }}
        >
          <div className="bg-white dark:bg-gray-800 rounded-xl shadow-xl w-full max-w-2xl max-h-[90vh] overflow-y-auto">
            {/* 모달 헤더 */}
            <div className="flex items-center justify-between px-6 py-4 border-b border-gray-200 dark:border-gray-700">
              <h2 className="text-lg font-bold text-gray-900 dark:text-gray-100">API 사용 신청</h2>
              <button
                type="button"
                onClick={handleCloseModal}
                className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors"
              >
                <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                  <path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
                </svg>
              </button>
            </div>

            {/* 성공 메시지 */}
            {modalSuccess ? (
              <div className="px-6 py-10 text-center">
                <div className="bg-green-50 dark:bg-green-900/30 border border-green-200 dark:border-green-700 rounded-lg p-6">
                  <h3 className="text-lg font-semibold text-green-800 dark:text-green-300 mb-2">신청이 완료되었습니다</h3>
                  <p className="text-green-700 dark:text-green-400 text-sm">관리자 승인 후 API Key가 생성됩니다.</p>
                </div>
              </div>
            ) : (
              <form onSubmit={handleModalSubmit} className="px-6 py-5 space-y-5">
                {/* 에러 메시지 */}
                {modalError && (
                  <div className="p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-700 text-red-700 dark:text-red-400 rounded-lg text-sm">
                    {modalError}
                  </div>
                )}

                {/* Key Name */}
                <div>
                  <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
                    Key Name <span className="text-red-500">*</span>
                  </label>
                  <input
                    type="text"
                    value={modalKeyName}
                    onChange={(e) => setModalKeyName(e.target.value)}
                    required
                    placeholder="API Key 이름을 입력하세요"
                    className="w-full border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none"
                  />
                </div>

                {/* 사용 목적 */}
                <div>
                  <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">사용 목적</label>
                  <textarea
                    value={modalPurpose}
                    onChange={(e) => setModalPurpose(e.target.value)}
                    rows={2}
                    placeholder="사용 목적을 입력하세요"
                    className="w-full border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none"
                  />
                </div>

                {/* 사용 기간 */}
                <div>
                  <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
                    사용 기간 <span className="text-red-500">*</span>
                  </label>
                  <div className="flex items-center gap-2 mb-2">
                    <button type="button" onClick={() => handleModalPresetPeriod(3)}
                      disabled={modalIsPermanent || modalUsagePeriodMode === 'custom'}
                      className={`px-3 py-1.5 text-sm rounded-lg border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 ${modalIsPermanent || modalUsagePeriodMode === 'custom' ? 'opacity-40 cursor-not-allowed' : 'hover:bg-blue-50 dark:hover:bg-gray-600'}`}>
                      3개월
                    </button>
                    <button type="button" onClick={() => handleModalPresetPeriod(6)}
                      disabled={modalIsPermanent || modalUsagePeriodMode === 'custom'}
                      className={`px-3 py-1.5 text-sm rounded-lg border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 ${modalIsPermanent || modalUsagePeriodMode === 'custom' ? 'opacity-40 cursor-not-allowed' : 'hover:bg-blue-50 dark:hover:bg-gray-600'}`}>
                      6개월
                    </button>
                    <button type="button" onClick={() => handleModalPresetPeriod(9)}
                      disabled={modalIsPermanent || modalUsagePeriodMode === 'custom'}
                      className={`px-3 py-1.5 text-sm rounded-lg border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 ${modalIsPermanent || modalUsagePeriodMode === 'custom' ? 'opacity-40 cursor-not-allowed' : 'hover:bg-blue-50 dark:hover:bg-gray-600'}`}>
                      9개월
                    </button>
                    <span className="text-gray-400 dark:text-gray-600 mx-1">|</span>
                    <button type="button" onClick={handleModalPermanent}
                      className={`px-3 py-1.5 text-sm rounded-lg border font-medium ${modalIsPermanent ? 'bg-indigo-600 text-white border-indigo-600' : 'text-indigo-600 border-indigo-300 dark:border-indigo-500 dark:text-indigo-400 hover:bg-indigo-50 dark:hover:bg-indigo-900/30'}`}>
                      영구
                    </button>
                    <span className="text-gray-400 dark:text-gray-600 mx-1">|</span>
                    <label className="flex items-center gap-2 text-sm text-gray-700 dark:text-gray-300 cursor-pointer select-none">
                      직접 선택
                      <button type="button"
                        onClick={() => {
                          setModalUsagePeriodMode(modalUsagePeriodMode === 'custom' ? 'preset' : 'custom');
                          setModalIsPermanent(false);
                        }}
                        className={`relative w-10 h-5 rounded-full transition-colors ${modalUsagePeriodMode === 'custom' && !modalIsPermanent ? 'bg-blue-600' : 'bg-gray-300 dark:bg-gray-600'}`}>
                        <span className={`absolute top-0.5 left-0.5 w-4 h-4 bg-white rounded-full shadow transition-transform ${modalUsagePeriodMode === 'custom' && !modalIsPermanent ? 'translate-x-5' : ''}`} />
                      </button>
                    </label>
                  </div>
                  {modalIsPermanent ? (
                    <div className="flex items-center gap-2 px-3 py-2 bg-indigo-50 dark:bg-indigo-900/30 border border-indigo-200 dark:border-indigo-700 rounded-lg">
                      <span className="text-indigo-700 dark:text-indigo-300 text-sm font-medium">영구 사용 (만료일 없음)</span>
                    </div>
                  ) : (
                    <div className="flex items-center gap-2">
                      <input type="date" value={modalUsageFromDate}
                        onChange={(e) => setModalUsageFromDate(e.target.value)}
                        readOnly={modalUsagePeriodMode !== 'custom'}
                        className={`border border-gray-300 dark:border-gray-600 rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none ${modalUsagePeriodMode !== 'custom' ? 'bg-gray-50 text-gray-500 dark:bg-gray-700 dark:text-gray-400' : 'bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100'}`} />
                      <span className="text-gray-500 dark:text-gray-400">~</span>
                      <input type="date" value={modalUsageToDate}
                        onChange={(e) => setModalUsageToDate(e.target.value)}
                        readOnly={modalUsagePeriodMode !== 'custom'}
                        className={`border border-gray-300 dark:border-gray-600 rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none ${modalUsagePeriodMode !== 'custom' ? 'bg-gray-50 text-gray-500 dark:bg-gray-700 dark:text-gray-400' : 'bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100'}`} />
                    </div>
                  )}
                </div>

                {/* 서비스 IP */}
                <div>
                  <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
                    서비스 IP <span className="text-red-500">*</span>
                  </label>
                  <input
                    type="text"
                    value={modalServiceIp}
                    onChange={(e) => setModalServiceIp(e.target.value)}
                    required
                    placeholder="예: 192.168.1.100"
                    className="w-full border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none"
                  />
                  <p className="text-xs text-gray-400 dark:text-gray-500 mt-1">발급받은 API Key로 프록시 서버에 요청하는 서비스 IP</p>
                </div>

                {/* 서비스 용도 + 하루 예상 요청량 */}
                <div className="grid grid-cols-2 gap-4">
                  <div>
                    <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
                      서비스 용도 <span className="text-red-500">*</span>
                    </label>
                    <select
                      value={modalServicePurpose}
                      onChange={(e) => setModalServicePurpose(e.target.value)}
                      required
                      className="w-full border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none"
                    >
                      <option value="">선택하세요</option>
                      <option value="로컬 환경">로컬 환경</option>
                      <option value="개발 서버">개발 서버</option>
                      <option value="검증 서버">검증 서버</option>
                      <option value="운영 서버">운영 서버</option>
                    </select>
                  </div>
                  <div>
                    <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
                      하루 예상 요청량 <span className="text-red-500">*</span>
                    </label>
                    <select
                      value={modalDailyRequestEstimate}
                      onChange={(e) => setModalDailyRequestEstimate(e.target.value)}
                      required
                      className="w-full border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none"
                    >
                      <option value="">선택하세요</option>
                      <option value="100">100 이하</option>
                      <option value="500">100~500</option>
                      <option value="1000">500~1,000</option>
                      <option value="5000">1,000~5,000</option>
                      <option value="10000">5,000~10,000</option>
                      <option value="50000">10,000 이상</option>
                    </select>
                  </div>
                </div>

                {/* API 선택 (도메인 기반 체크박스 트리) */}
                <div className="border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden">
                  <div className="flex items-center justify-between px-4 py-2.5 bg-gray-50 dark:bg-gray-700 border-b border-gray-200 dark:border-gray-700">
                    <h3 className="text-sm font-semibold text-gray-900 dark:text-gray-100">API 선택</h3>
                    <input
                      type="text"
                      value={modalApiSearch}
                      onChange={(e) => setModalApiSearch(e.target.value)}
                      placeholder="API 검색..."
                      className="bg-white dark:bg-gray-600 border border-gray-200 dark:border-gray-500 rounded-lg px-2.5 py-1 text-xs text-gray-900 dark:text-gray-100 placeholder-gray-400 focus:ring-1 focus:ring-blue-500 focus:outline-none w-40"
                    />
                  </div>
                  <div className="max-h-56 overflow-y-auto">
                    {(() => {
                      const domainMap = new Map<string, { apiId: number; apiName: string }[]>();
                      for (const svc of modalCatalog) {
                        for (const dg of svc.domains) {
                          const key = /^[a-zA-Z\s\-_]+$/.test(dg.domain) ? dg.domain.toUpperCase() : dg.domain;
                          const existing = domainMap.get(key) ?? [];
                          for (const a of dg.apis) {
                            if (!existing.some((e) => e.apiId === a.apiId)) {
                              if (!modalApiSearch.trim() || a.apiName.toLowerCase().includes(modalApiSearch.toLowerCase())) {
                                existing.push({ apiId: a.apiId, apiName: a.apiName });
                              }
                            }
                          }
                          if (existing.length > 0) domainMap.set(key, existing);
                        }
                      }
                      const domains = Array.from(domainMap.entries());
                      if (domains.length === 0) return <p className="text-xs text-gray-400 text-center py-6">검색 결과가 없습니다</p>;
                      return domains.map(([domain, apis]) => {
                        const isExpanded = modalExpandedDomains.has(domain);
                        const allSelected = apis.every((a) => modalSelectedApiIds.has(a.apiId));
                        const someSelected = !allSelected && apis.some((a) => modalSelectedApiIds.has(a.apiId));
                        return (
                          <div key={domain}>
                            <div
                              className="flex items-center gap-2 px-4 py-2 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700/50 border-b border-gray-100 dark:border-gray-700/50"
                              onClick={() => setModalExpandedDomains((prev) => { const n = new Set(prev); n.has(domain) ? n.delete(domain) : n.add(domain); return n; })}
                            >
                              <svg className={`h-3.5 w-3.5 text-gray-400 transition-transform ${isExpanded ? 'rotate-90' : ''}`} fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" /></svg>
                              <input
                                type="checkbox"
                                checked={allSelected}
                                ref={(el) => { if (el) el.indeterminate = someSelected; }}
                                onChange={() => {
                                  setModalSelectedApiIds((prev) => {
                                    const n = new Set(prev);
                                    apis.forEach((a) => allSelected ? n.delete(a.apiId) : n.add(a.apiId));
                                    return n;
                                  });
                                }}
                                onClick={(e) => e.stopPropagation()}
                                className="rounded"
                              />
                              <span className="text-sm font-semibold text-gray-900 dark:text-gray-100">{domain}</span>
                              <span className="text-xs text-gray-400">{apis.length}</span>
                            </div>
                            {isExpanded && apis.map((a) => (
                              <div
                                key={a.apiId}
                                className={`flex items-center gap-2 pl-12 pr-4 py-2 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700/30 border-b border-gray-50 dark:border-gray-700/30 ${modalSelectedApiIds.has(a.apiId) ? 'bg-blue-50/50 dark:bg-blue-900/10' : ''}`}
                                onClick={() => setModalSelectedApiIds((prev) => { const n = new Set(prev); n.has(a.apiId) ? n.delete(a.apiId) : n.add(a.apiId); return n; })}
                              >
                                <input
                                  type="checkbox"
                                  checked={modalSelectedApiIds.has(a.apiId)}
                                  onChange={() => setModalSelectedApiIds((prev) => { const n = new Set(prev); n.has(a.apiId) ? n.delete(a.apiId) : n.add(a.apiId); return n; })}
                                  onClick={(e) => e.stopPropagation()}
                                  className="rounded"
                                />
                                <span className="text-sm text-gray-900 dark:text-gray-100 truncate">{a.apiName}</span>
                              </div>
                            ))}
                          </div>
                        );
                      });
                    })()}
                  </div>
                </div>

                {/* 신청 API 요약 */}
                {modalSelectedApiIds.size > 0 && (
                  <div className="bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-700 rounded-lg px-4 py-3">
                    <p className="text-xs font-medium text-blue-600 dark:text-blue-400 uppercase tracking-wide">
                      신청 API ({modalSelectedApiIds.size}개 선택)
                    </p>
                  </div>
                )}

                {/* 모달 하단 버튼 */}
                <div className="flex justify-end gap-3 pt-2">
                  <button
                    type="button"
                    onClick={handleCloseModal}
                    className="px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 text-sm font-medium transition-colors"
                  >
                    취소
                  </button>
                  <button
                    type="submit"
                    disabled={modalIsSubmitting}
                    className="px-4 py-2 rounded-lg bg-blue-600 hover:bg-blue-700 disabled:bg-blue-300 text-white text-sm font-medium transition-colors"
                  >
                    {modalIsSubmitting ? '신청 중...' : '신청하기'}
                  </button>
                </div>
              </form>
            )}
          </div>
        </div>
      )}
    </div>
  );
};

export default ApiHubApiDetailPage;
