import { useState, useEffect } from 'react';
import { getDownloadInfo } from '../../api/download';
import { tryRefresh } from '../../api/client';
import './AdminCommon.css';

const BASE = import.meta.env.VITE_API_BASE_URL || '';

function sendXhr(url, token, file, { onProgress, onDone, onError }) {
  const xhr = new XMLHttpRequest();

  xhr.upload.onprogress = (event) => {
    if (event.lengthComputable) {
      onProgress(Math.round((event.loaded / event.total) * 100));
    }
  };

  xhr.onload = () => onDone(xhr);
  xhr.onerror = () => onError();

  xhr.open('POST', url);
  xhr.setRequestHeader('Authorization', `Bearer ${token}`);
  xhr.setRequestHeader('Content-Type', 'application/octet-stream');
  xhr.send(file);
}

function UploadForm({ title, hint, accept, endpoint, onSuccess }) {
  const [file, setFile] = useState(null);
  const [uploading, setUploading] = useState(false);
  const [progress, setProgress] = useState(0);
  const [error, setError] = useState('');

  const handleFileChange = (e) => {
    setFile(e.target.files[0] || null);
    setError('');
    setProgress(0);
  };

  const handleUpload = (e) => {
    e.preventDefault();
    if (!file) return;

    const token = localStorage.getItem('token');
    const url = `${BASE}${endpoint}?filename=${encodeURIComponent(file.name)}`;

    setUploading(true);
    setError('');

    const handleDone = (xhr) => {
      // 401 시 토큰 갱신 후 재시도
      if (xhr.status === 401) {
        tryRefresh()
          .then((newToken) => {
            sendXhr(url, newToken, file, {
              onProgress: (p) => setProgress(p),
              onDone: (retryXhr) => {
                setUploading(false);
                if (retryXhr.status === 401) {
                  window.dispatchEvent(new Event('auth:unauthorized'));
                  return;
                }
                parseXhrResponse(retryXhr);
              },
              onError: handleError,
            });
          })
          .catch(() => {
            setUploading(false);
            window.dispatchEvent(new Event('auth:unauthorized'));
          });
        return;
      }
      setUploading(false);
      parseXhrResponse(xhr);
    };

    const parseXhrResponse = (xhr) => {
      try {
        const body = JSON.parse(xhr.responseText || '{}');
        if (xhr.status >= 200 && xhr.status < 300) {
          onSuccess(body);
          setFile(null);
          setProgress(0);
        } else {
          setError(body.error || '업로드에 실패했습니다.');
          setProgress(0);
        }
      } catch {
        if (xhr.status >= 200 && xhr.status < 300) {
          setError('응답을 처리할 수 없습니다.');
        } else {
          setError('업로드에 실패했습니다.');
        }
        setProgress(0);
      }
    };

    const handleError = () => {
      setUploading(false);
      setError('네트워크 오류가 발생했습니다.');
      setProgress(0);
    };

    sendXhr(url, token, file, {
      onProgress: (p) => setProgress(p),
      onDone: handleDone,
      onError: handleError,
    });
  };

  return (
    <form className="admin-form" onSubmit={handleUpload}>
      <div className="admin-field">
        <label className="admin-label">{title}</label>
        <input
          type="file"
          accept={accept}
          className="admin-input-file"
          onChange={handleFileChange}
          disabled={uploading}
        />
        <span className="admin-field-hint">{hint}</span>
      </div>

      {uploading && (
        <div className="admin-upload-progress">
          <div className="admin-upload-bar" style={{ width: `${progress}%` }} />
          <span className="admin-upload-pct">{progress}%</span>
        </div>
      )}

      {error && <p className="admin-error">{error}</p>}

      <div className="admin-form-actions">
        <button className="btn-admin-primary" type="submit" disabled={uploading || !file}>
          {uploading ? `업로드 중... (${progress}%)` : '업로드'}
        </button>
      </div>
    </form>
  );
}

export default function DownloadAdmin() {
  const [info, setInfo] = useState(null);

  useEffect(() => {
    getDownloadInfo().then(setInfo).catch((err) => {
      console.error('다운로드 정보 로드 실패:', err);
    });
  }, []);

  return (
    <div className="admin-section">
      <h2 className="admin-section-title">게임 배포 관리</h2>

      {/* 런처 섹션 */}
      <div className="admin-deploy-block">
        <div className="admin-deploy-header">
          <span className="admin-deploy-label">런처</span>
          {info?.launcherUrl && (
            <div className="admin-meta-row">
              {info.launcherSize && <span className="admin-meta-item">{info.launcherSize}</span>}
            </div>
          )}
        </div>
        <UploadForm
          title="launcher.exe"
          hint="빌드된 launcher.exe 파일을 업로드하세요."
          accept=".exe"
          endpoint="/api/download/upload/launcher"
          onSuccess={setInfo}
        />
      </div>

      {/* 게임 섹션 */}
      <div className="admin-deploy-block">
        <div className="admin-deploy-header">
          <span className="admin-deploy-label">게임</span>
          {info?.url && (
            <div className="admin-meta-row">
              {info.version && <span className="admin-meta-item">{info.version}</span>}
              {info.fileName && <span className="admin-meta-item">{info.fileName}</span>}
              {info.fileSize && <span className="admin-meta-item">{info.fileSize}</span>}
              {info.fileHash && (
                <span className="admin-meta-item admin-meta-hash" title={info.fileHash}>
                  SHA256: {info.fileHash.slice(0, 12)}...
                </span>
              )}
            </div>
          )}
        </div>
        <UploadForm
          title="게임 파일 (zip)"
          hint="A301.exe가 포함된 zip 파일을 업로드하세요. 버전·크기·해시가 자동으로 추출됩니다."
          accept=".zip"
          endpoint="/api/download/upload/game"
          onSuccess={setInfo}
        />
      </div>
    </div>
  );
}
