// MyAlbumsView — server-stored personal albums, accessible from any device.

const MY_ALBUMS_STORAGE_BASE = window.SongfilmApiConfig.getBase("storage");
const MY_ALBUMS_RENDERER_BASE = window.SongfilmApiConfig.getBase("remotion");

function formatMyAlbumSavedAt(iso) {
  if (!iso) return "";
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return "";
  const pad = (n) => String(n).padStart(2, "0");
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
}

function formatShareDate(iso) {
  if (!iso) return "";
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return "";
  return d.toLocaleDateString('ko-KR', {
    year: 'numeric', month: '2-digit', day: '2-digit',
    hour: '2-digit', minute: '2-digit',
  });
}

function getShareStatus(share) {
  if (!share?.shared || !share.shareId) return 'none';
  if (share.revokedAt) return 'revoked';
  const expiresMs = new Date(share.expiresAt || 0).getTime();
  if (Number.isFinite(expiresMs) && Date.now() > expiresMs) return 'expired';
  return 'active';
}

function getShareStatusLabel(share) {
  const status = getShareStatus(share);
  if (status === 'active') return `공유 중 · ${formatShareDate(share.expiresAt)} 만료`;
  if (status === 'expired') return `만료됨 · ${formatShareDate(share.expiresAt)}`;
  if (status === 'revoked') return `회수됨 · ${formatShareDate(share.revokedAt)}`;
  return '공유 안 됨';
}

function buildShareUrl(shareId) {
  return `https://songfilm-pub.jskimoffice.com?sharedID=${shareId}`;
}

function MyAlbumsView({
  albums,
  selectedAlbumId,
  loading,
  error,
  onRefresh,
  onSelectAlbum,
  onExit,
  onDeleteAlbum,
  onCopyToWorkspace,
}) {
  const audioUrlCacheRef = React.useRef(new Map());
  const [shareLinkStates, setShareLinkStates] = React.useState({});
  const [shareOverrides, setShareOverrides] = React.useState({});

  React.useEffect(() => {
    setShareOverrides({});
  }, [albums]);

  const getAlbumShare = React.useCallback((item, album) => {
    const albumId = item?.id || "";
    return shareOverrides[albumId] || item?.share || album?.share || { shared: false };
  }, [shareOverrides]);

  const applyShareUpdate = React.useCallback((albumId, share) => {
    setShareOverrides((prev) => ({ ...prev, [albumId]: share || { shared: false } }));
  }, []);

  const requestShare = React.useCallback(async (albumId, options = {}) => {
    const session = window.SongfilmAuth?.getSession?.();
    if (!session?.token) throw new Error('로그인이 필요합니다.');
    const res = await fetch(`${MY_ALBUMS_STORAGE_BASE}/user-albums/${encodeURIComponent(albumId)}/share-link`, {
      method: options.method || 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${session.token}`,
      },
      body: options.body ? JSON.stringify(options.body) : undefined,
    });
    const data = await res.json().catch(() => ({}));
    if (!res.ok) throw new Error(data.error || '공유 링크 처리 실패');
    if (data.share) applyShareUpdate(albumId, data.share);
    return data;
  }, [applyShareUpdate]);

  const createShareLink = React.useCallback(async (albumId) => {
    setShareLinkStates((prev) => ({ ...prev, [albumId]: 'loading' }));
    try {
      const data = await requestShare(albumId, { method: 'POST' });
      const shareUrl = buildShareUrl(data.shareId);
      await navigator.clipboard.writeText(shareUrl);

      setShareLinkStates((prev) => ({ ...prev, [albumId]: 'copied' }));
      window.toast?.(`공유 링크 복사 완료 · ${formatShareDate(data.expiresAt)}까지 유효합니다.`);
      setTimeout(() => {
        setShareLinkStates((prev) => ({ ...prev, [albumId]: null }));
      }, 3000);
    } catch (err) {
      window.toast?.(err.message || '공유 링크 생성에 실패했습니다.');
      setShareLinkStates((prev) => ({ ...prev, [albumId]: null }));
    }
  }, [requestShare]);

  const copyExistingShareLink = React.useCallback(async (albumId, share) => {
    if (!share?.shareId) return createShareLink(albumId);
    setShareLinkStates((prev) => ({ ...prev, [albumId]: 'loading' }));
    try {
      const data = await requestShare(albumId, { method: 'POST' });
      await navigator.clipboard.writeText(buildShareUrl(data.shareId || share.shareId));
      setShareLinkStates((prev) => ({ ...prev, [albumId]: 'copied' }));
      window.toast?.('기존 공유 링크를 복사했습니다.');
      setTimeout(() => {
        setShareLinkStates((prev) => ({ ...prev, [albumId]: null }));
      }, 3000);
    } catch (err) {
      window.toast?.(err.message || '공유 링크 복사에 실패했습니다.');
    }
  }, [createShareLink]);

  const changeShareExpiry = React.useCallback(async (albumId) => {
    const daysText = window.prompt('공유 링크 만료 기간을 며칠 뒤로 변경할까요?', '5');
    if (daysText == null) return;
    const days = Number(daysText);
    if (!Number.isFinite(days) || days <= 0) {
      window.toast?.('1 이상의 숫자를 입력해 주세요.');
      return;
    }
    setShareLinkStates((prev) => ({ ...prev, [albumId]: 'loading' }));
    try {
      const expiresAt = new Date(Date.now() + days * 24 * 60 * 60 * 1000).toISOString();
      await requestShare(albumId, { method: 'PATCH', body: { expiresAt } });
      window.toast?.(`만료일을 ${formatShareDate(expiresAt)}로 변경했습니다.`);
    } catch (err) {
      window.toast?.(err.message || '만료일 변경에 실패했습니다.');
    } finally {
      setShareLinkStates((prev) => ({ ...prev, [albumId]: null }));
    }
  }, [requestShare]);

  const revokeShareLink = React.useCallback(async (albumId) => {
    if (!window.confirm('이 공유 링크의 접근 권한을 회수할까요? 이미 전달된 링크도 더 이상 재생할 수 없습니다.')) return;
    setShareLinkStates((prev) => ({ ...prev, [albumId]: 'loading' }));
    try {
      await requestShare(albumId, { method: 'DELETE' });
      window.toast?.('공유 링크 권한을 회수했습니다.');
    } catch (err) {
      window.toast?.(err.message || '공유 링크 회수에 실패했습니다.');
    } finally {
      setShareLinkStates((prev) => ({ ...prev, [albumId]: null }));
    }
  }, [requestShare]);

  const hasAudioAsset = (song) => (
    !!(song?.audioServerUrl || song?.audio?.filename || song?.audio?.url || song?.exportState?.audioFilename || song?.audioStorageKey)
  );
  const hasVideoAsset = (song) => !!(song?.exportState?.videoFilename || song?.exportState?.jobId);

  const resolveAudioUrl = React.useCallback(async (song) => {
    const cacheKey = song?.id || song?.filename || song?.title || "";
    const cached = audioUrlCacheRef.current.get(cacheKey);
    if (cached) return cached;

    const serverRef = String(song?.audioServerUrl || song?.audio?.filename || song?.audio?.url || song?.exportState?.audioFilename || "").trim();
    if (serverRef) {
      const built = window.SongfilmApiConfig?.buildMediaUrl
        ? window.SongfilmApiConfig.buildMediaUrl("audio", serverRef)
        : `${MY_ALBUMS_STORAGE_BASE}/audio/${encodeURIComponent(serverRef)}`;
      audioUrlCacheRef.current.set(cacheKey, built);
      return built;
    }

    const restored = await window.SongfilmSongStorage?.restoreAudioUrl?.(song);
    if (restored) audioUrlCacheRef.current.set(cacheKey, restored);
    return restored || "";
  }, []);

  const resolveVideoUrl = React.useCallback((song) => {
    const videoFilename = String(song?.exportState?.videoFilename || "").trim();
    if (videoFilename) {
      return window.SongfilmApiConfig?.buildMediaUrl
        ? window.SongfilmApiConfig.buildMediaUrl("video", videoFilename)
        : `${MY_ALBUMS_STORAGE_BASE}/video/${encodeURIComponent(videoFilename)}`;
    }
    const jobId = String(song?.exportState?.jobId || "").trim();
    if (jobId) return `${MY_ALBUMS_RENDERER_BASE}/render/${jobId}/file`;
    return "";
  }, []);

  const renderPanelExtra = React.useCallback((item, album) => {
    const { Icon } = window;
    const savedAt  = album?.myAlbumSavedAt || item?.savedAt || "";
    const albumId  = item?.id || "";
    const shareState = shareLinkStates[albumId];
    const share = getAlbumShare(item, album);
    const shareStatus = getShareStatus(share);
    const isBusy = shareState === "loading";
    return (
      <div style={{
        display: "flex", alignItems: "center", flexWrap: "wrap", gap: 8,
        padding: "10px 0 4px", borderTop: "1px solid var(--line)",
      }} data-role="main-my-albums-panel-actions-row">
        {savedAt && (
          <span style={{
            fontSize: 11.5, color: "var(--ink-4)",
            fontFamily: "var(--font-mono)", marginRight: "auto",
      }}>
            저장: {formatMyAlbumSavedAt(savedAt)}
          </span>
        )}
        <span style={{
          fontSize: 11.5,
          color: shareStatus === 'active' ? 'var(--accent)' : 'var(--ink-4)',
          fontFamily: 'var(--font-mono)',
          marginRight: savedAt ? 0 : 'auto',
        }} data-role="main-my-albums-share-status-text">
          {getShareStatusLabel(share)}
        </span>
        <button
          className="pill-btn sm"
          data-role="main-my-albums-share-link-copy-btn"
          onClick={(e) => {
            e.stopPropagation();
            if (shareStatus === 'active') copyExistingShareLink(albumId, share);
            else createShareLink(albumId);
          }}
          disabled={isBusy}
          title={shareStatus === 'active'
            ? '기존 공유 링크를 클립보드에 다시 복사합니다'
            : '공유 링크를 생성하여 클립보드에 복사합니다'}
        >
          {isBusy
            ? <><Icon.Loader size={11}/> 생성 중...</>
            : shareState === "copied"
              ? <><Icon.Check size={11}/> 복사됨</>
              : shareStatus === 'active'
                ? <><Icon.Link size={11}/> 링크 다시 복사</>
                : <><Icon.Link size={11}/> 공유 링크 복사</>}
        </button>
        {(shareStatus === 'active' || shareStatus === 'expired') && (
          <>
            <button
              className="pill-btn sm"
              data-role="main-my-albums-share-expiry-change-btn"
              onClick={(e) => { e.stopPropagation(); changeShareExpiry(albumId); }}
              disabled={isBusy}
              title="공유 링크 만료 기간을 변경합니다"
            >
              <Icon.Edit size={11}/> 만료 변경
            </button>
            <button
              className="pill-btn sm danger"
              data-role="main-my-albums-share-revoke-btn"
              onClick={(e) => { e.stopPropagation(); revokeShareLink(albumId); }}
              disabled={isBusy}
              title="공유 링크 접근 권한을 회수합니다"
            >
              <Icon.Trash size={11}/> 권한 회수
            </button>
          </>
        )}
        <button
          className="pill-btn sm"
          data-role="main-my-albums-copy-workspace-btn"
          onClick={(e) => { e.stopPropagation(); onCopyToWorkspace?.(item); }}
          title="이 앨범을 내 워크스페이스에 복사합니다"
        >
          <Icon.Download size={11}/> Workspace로 복사
        </button>
        <button
          className="pill-btn sm danger"
          data-role="main-my-albums-delete-btn"
          onClick={(e) => { e.stopPropagation(); onDeleteAlbum?.(item?.id || ""); }}
          title="내 앨범에서 삭제합니다"
        >
          <Icon.Trash size={11}/> 삭제
        </button>
      </div>
    );
  }, [
    shareLinkStates,
    getAlbumShare,
    createShareLink,
    copyExistingShareLink,
    changeShareExpiry,
    revokeShareLink,
    onCopyToWorkspace,
    onDeleteAlbum,
  ]);

  return (
    <AlbumPlayerView
      albums={albums}
      selectedAlbumId={selectedAlbumId}
      onSelectAlbum={onSelectAlbum}
      loading={loading}
      error={error}
      onRefresh={onRefresh}
      onExit={onExit}
      copy={{
        headerLabel: "MY ALBUMS",
        title: "내 앨범",
        subtitle: "서버에 보관된 나의 앨범입니다. 어느 기기에서든 접근해서 재생할 수 있습니다.",
        loadingText: "내 앨범을 불러오는 중입니다.",
        emptyText: "보관된 앨범이 없습니다. 앨범 홈에서 '내 앨범에 저장'을 눌러 워크스페이스 앨범을 저장하세요.",
      }}
      hasAudioAsset={hasAudioAsset}
      hasVideoAsset={hasVideoAsset}
      resolveAudioUrl={resolveAudioUrl}
      resolveVideoUrl={resolveVideoUrl}
      getAlbumItems={(items) => items}
      getAlbumFromItem={(item) => item?.album || null}
      getItemId={(item) => item?.id || ""}
      getCardTitle={(item, album) => item?.title || album?.title || "Untitled Album"}
      getCardSubtitle={(item, album) => {
        const songCount = item?.songCount ?? album?.songs?.length ?? 0;
        const savedAt = item?.myAlbumSavedAt
          ? ` · ${formatMyAlbumSavedAt(item.myAlbumSavedAt)} 저장`
          : "";
        return `${item?.artist || album?.artist || "Unknown"} · ${songCount}곡${savedAt}`;
      }}
      getCardBadge={(item, album) => album?.year || "MY"}
      getPanelLabel={() => "내 앨범"}
      getPanelPublisher={(item, album) => album?.artist || ""}
      getSelectedMissingText={() => "선택한 앨범 데이터를 불러오지 못했습니다."}
      renderPanelExtra={renderPanelExtra}
    />
  );
}

Object.assign(window, { MyAlbumsView });
