/**
 * task-2334: 카드 상세 페이지 좌우 네비게이션 + sessionStorage 카드 리스트
 *
 * 검증 대상:
 * - sessionStorage 키 네이밍 컨벤션 (insuwiki_card_list_{tab})
 * - prev/next id 계산 로직 (배열 인덱스 기반)
 * - 첫/마지막 카드 경계 조건
 */

import { describe, it, expect, beforeEach } from 'vitest';

const SESSION_KEY = (tab: string) => `insuwiki_card_list_${tab}`;

function readCardList(tab: string, storage: Storage): string[] {
  const raw = storage.getItem(SESSION_KEY(tab));
  if (!raw) return [];
  try {
    const parsed = JSON.parse(raw);
    return Array.isArray(parsed) ? parsed : [];
  } catch {
    return [];
  }
}

function computePrevNext(currentId: string, list: string[]): { prev: string | null; next: string | null } {
  const idx = list.indexOf(currentId);
  if (idx === -1) return { prev: null, next: null };
  return {
    prev: idx > 0 ? list[idx - 1] : null,
    next: idx < list.length - 1 ? list[idx + 1] : null,
  };
}

class MemoryStorage implements Storage {
  private data: Record<string, string> = {};
  get length() { return Object.keys(this.data).length; }
  clear() { this.data = {}; }
  getItem(k: string) { return this.data[k] ?? null; }
  key(i: number) { return Object.keys(this.data)[i] ?? null; }
  removeItem(k: string) { delete this.data[k]; }
  setItem(k: string, v: string) { this.data[k] = String(v); }
}

describe('카드 리스트 sessionStorage 네이밍', () => {
  it('탭별로 분리된 키를 사용해야 한다', () => {
    expect(SESSION_KEY('wiki')).toBe('insuwiki_card_list_wiki');
    expect(SESSION_KEY('my')).toBe('insuwiki_card_list_my');
    expect(SESSION_KEY('daily')).toBe('insuwiki_card_list_daily');
  });
});

describe('readCardList — sessionStorage 카드 리스트 로드', () => {
  let storage: MemoryStorage;
  beforeEach(() => {
    storage = new MemoryStorage();
  });

  it('키가 없으면 빈 배열을 반환한다', () => {
    expect(readCardList('wiki', storage)).toEqual([]);
  });

  it('JSON 배열을 그대로 반환한다', () => {
    storage.setItem('insuwiki_card_list_wiki', JSON.stringify(['a', 'b', 'c']));
    expect(readCardList('wiki', storage)).toEqual(['a', 'b', 'c']);
  });

  it('잘못된 JSON이면 빈 배열을 반환한다', () => {
    storage.setItem('insuwiki_card_list_wiki', '{not json');
    expect(readCardList('wiki', storage)).toEqual([]);
  });

  it('배열이 아닌 JSON이면 빈 배열을 반환한다', () => {
    storage.setItem('insuwiki_card_list_wiki', JSON.stringify({ foo: 'bar' }));
    expect(readCardList('wiki', storage)).toEqual([]);
  });
});

describe('computePrevNext — 좌우 네비게이션 인덱스 계산', () => {
  const list = ['id-0', 'id-1', 'id-2', 'id-3', 'id-4'];

  it('중간 카드는 prev/next 모두 존재', () => {
    expect(computePrevNext('id-2', list)).toEqual({ prev: 'id-1', next: 'id-3' });
  });

  it('첫 카드는 prev=null', () => {
    expect(computePrevNext('id-0', list)).toEqual({ prev: null, next: 'id-1' });
  });

  it('마지막 카드는 next=null', () => {
    expect(computePrevNext('id-4', list)).toEqual({ prev: 'id-3', next: null });
  });

  it('리스트에 없는 id는 prev/next 모두 null (외부 링크 진입)', () => {
    expect(computePrevNext('unknown', list)).toEqual({ prev: null, next: null });
  });

  it('단일 카드 리스트는 prev/next 모두 null', () => {
    expect(computePrevNext('only', ['only'])).toEqual({ prev: null, next: null });
  });

  it('빈 리스트는 prev/next 모두 null', () => {
    expect(computePrevNext('any', [])).toEqual({ prev: null, next: null });
  });
});
