import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { TOAST_KEY_PREFIX, TOAST_SUPPRESS_MS, setupLicenseToast, resolveToastKey, shouldShowToast } from './index';

describe('shouldShowToast', () => {
  beforeEach(() => {
    localStorage.clear();
  });

  it('localStorageが空のときtrueを返す', () => {
    expect(shouldShowToast(TOAST_KEY_PREFIX)).toBe(true);
  });

  it('抑制期限が切れているときtrueを返す', () => {
    localStorage.setItem(TOAST_KEY_PREFIX, String(Date.now() - 1));
    expect(shouldShowToast(TOAST_KEY_PREFIX)).toBe(true);
  });

  it('抑制期限が有効なときfalseを返す', () => {
    localStorage.setItem(TOAST_KEY_PREFIX, String(Date.now() + TOAST_SUPPRESS_MS));
    expect(shouldShowToast(TOAST_KEY_PREFIX)).toBe(false);
  });
});

describe('resolveToastKey', () => {
  it('data-toast-key がなければデフォルトキーを返す', () => {
    const item = document.createElement('div');
    expect(resolveToastKey(item)).toBe(TOAST_KEY_PREFIX);
  });

  it('data-toast-key があればprefixを付けたキーを返す', () => {
    const item = document.createElement('div');
    item.dataset.toastKey = 'development';
    expect(resolveToastKey(item)).toBe(`${TOAST_KEY_PREFIX}-development`);
  });
});

describe('setupLicenseToast', () => {
  beforeEach(() => {
    localStorage.clear();
    vi.useFakeTimers();
    document.body.innerHTML = `
      <div class="js-admin-toast-toggle acms-admin-toast-closed" style="display: none">
        <button data-admin-toast-close></button>
      </div>
    `;
  });

  afterEach(() => {
    vi.useRealTimers();
    document.body.innerHTML = '';
  });

  describe('抑制期間中', () => {
    beforeEach(() => {
      localStorage.setItem(TOAST_KEY_PREFIX, String(Date.now() + TOAST_SUPPRESS_MS));
    });

    it('トースト要素をDOMから削除する', () => {
      setupLicenseToast();
      expect(document.querySelector('.js-admin-toast-toggle')).toBeNull();
    });

    it('複数要素があればすべて削除する', () => {
      document.body.innerHTML = `
        <div class="js-admin-toast-toggle acms-admin-toast-closed"></div>
        <div class="js-admin-toast-toggle acms-admin-toast-closed"></div>
      `;
      setupLicenseToast();
      expect(document.querySelectorAll('.js-admin-toast-toggle')).toHaveLength(0);
    });
  });

  describe('抑制期間外', () => {
    it('display:noneを解除してトーストを表示状態にする', () => {
      setupLicenseToast();
      const toast = document.querySelector<HTMLElement>('.js-admin-toast-toggle');
      expect(toast?.style.display).toBe('');
    });

    it('closeClassを外してトーストを全体表示する', () => {
      setupLicenseToast();
      const toast = document.querySelector('.js-admin-toast-toggle');
      expect(toast?.classList.contains('acms-admin-toast-closed')).toBe(false);
    });

    it('5秒後にcloseClassを付与して引っ込める', () => {
      setupLicenseToast();
      vi.advanceTimersByTime(5000);
      const toast = document.querySelector('.js-admin-toast-toggle');
      expect(toast?.classList.contains('acms-admin-toast-closed')).toBe(true);
    });

    it('mouseenterでcloseClassを外して全体表示する', () => {
      setupLicenseToast();
      vi.advanceTimersByTime(5000);
      const toast = document.querySelector<HTMLElement>('.js-admin-toast-toggle');
      toast?.dispatchEvent(new MouseEvent('mouseenter'));
      expect(toast?.classList.contains('acms-admin-toast-closed')).toBe(false);
    });

    it('mouseleaveでcloseClassを付与して引っ込める', () => {
      setupLicenseToast();
      const toast = document.querySelector<HTMLElement>('.js-admin-toast-toggle');
      toast?.dispatchEvent(new MouseEvent('mouseleave'));
      expect(toast?.classList.contains('acms-admin-toast-closed')).toBe(true);
    });
  });

  describe('閉じるボタン', () => {
    it('クリックでlocalStorageに24時間後の抑制期限を書き込む', () => {
      const now = 1000000000000;
      vi.spyOn(Date, 'now').mockReturnValue(now);

      setupLicenseToast();
      document.querySelector<HTMLButtonElement>('[data-admin-toast-close]')?.click();

      expect(localStorage.getItem(TOAST_KEY_PREFIX)).toBe(String(now + TOAST_SUPPRESS_MS));
    });

    it('クリックでtransitionend後にトーストをDOMから削除する', () => {
      setupLicenseToast();
      const toast = document.querySelector<HTMLElement>('.js-admin-toast-toggle');
      document.querySelector<HTMLButtonElement>('[data-admin-toast-close]')?.click();
      toast?.dispatchEvent(new Event('transitionend'));

      expect(document.querySelector('.js-admin-toast-toggle')).toBeNull();
    });

    it('transitionend前はまだDOMに残っている', () => {
      setupLicenseToast();
      document.querySelector<HTMLButtonElement>('[data-admin-toast-close]')?.click();

      expect(document.querySelector('.js-admin-toast-toggle')).not.toBeNull();
    });

    // モバイル時は `.acms-admin-toast-static-md` で `transform: translateY(0)` が既に当たっており
    // 同じ値を再設定しても transition が発火しないため、transitionend を待つだけでは要素が削除されない
    it('transitionend が発火しなくても 500ms 経過で削除される（モバイル fallback）', () => {
      setupLicenseToast();
      document.querySelector<HTMLButtonElement>('[data-admin-toast-close]')?.click();

      vi.advanceTimersByTime(500);

      expect(document.querySelector('.js-admin-toast-toggle')).toBeNull();
    });

    it('transitionend が先に発火しても fallback で二重削除にならない', () => {
      setupLicenseToast();
      const toast = document.querySelector<HTMLElement>('.js-admin-toast-toggle');
      document.querySelector<HTMLButtonElement>('[data-admin-toast-close]')?.click();

      toast?.dispatchEvent(new Event('transitionend'));
      // fallback タイマーまで進めても問題が起きないこと
      expect(() => vi.advanceTimersByTime(500)).not.toThrow();
      expect(document.querySelector('.js-admin-toast-toggle')).toBeNull();
    });
  });

  describe('data-toast-key による個別キー管理', () => {
    it('data-toast-key が異なるトーストは独立して管理される', () => {
      document.body.innerHTML = `
        <div class="js-admin-toast-toggle acms-admin-toast-closed" data-toast-key="development"></div>
        <div class="js-admin-toast-toggle acms-admin-toast-closed" data-toast-key="trial"></div>
      `;
      // development だけ抑制
      localStorage.setItem(`${TOAST_KEY_PREFIX}-development`, String(Date.now() + TOAST_SUPPRESS_MS));

      setupLicenseToast();

      expect(document.querySelector('[data-toast-key="development"]')).toBeNull();
      expect(document.querySelector('[data-toast-key="trial"]')).not.toBeNull();
    });

    it('閉じるボタンクリックでdata-toast-keyに対応したキーに書き込む', () => {
      document.body.innerHTML = `
        <div class="js-admin-toast-toggle acms-admin-toast-closed" data-toast-key="development">
          <button data-admin-toast-close></button>
        </div>
      `;
      const now = 1000000000000;
      vi.spyOn(Date, 'now').mockReturnValue(now);

      setupLicenseToast();
      document.querySelector<HTMLButtonElement>('[data-admin-toast-close]')?.click();

      expect(localStorage.getItem(`${TOAST_KEY_PREFIX}-development`)).toBe(String(now + TOAST_SUPPRESS_MS));
      expect(localStorage.getItem(TOAST_KEY_PREFIX)).toBeNull();
    });
  });
});
