/**
 * 持久化中间件基础设施。
 *
 * 所有 Store 统一使用 zustand 官方 persist + createJSONStorage(localStorage)。
 * zustand 只有在「新 key 下已存在数据」时才会执行 migrate，因此旧 key/旧格式
 * 不能只靠 migrate 迁移：这里通过 StateStorage.getItem 的旧值回退（把旧数据
 * 包装成 version:1 的 persist envelope），保证升级后首次加载就能触发 migrate，
 * 并在首次写入新格式时清理旧 key。
 */
import { createJSONStorage, type StateStorage } from 'zustand/middleware';
import type { AppPersistedState, DockTab } from '../app/appTypes';
import type { PermissionPersistedState } from '../permission/permissionTypes';
import type { UserInfo, UserPersistedState } from '../user/userTypes';

export const AUTH_STORAGE_NAME = 'gongxue-auth';
export const LEGACY_TOKEN_KEY = 'token';
export const LEGACY_USER_KEY = 'user';

export const PERMISSION_STORAGE_NAME = 'permissions';

export const APP_UI_STORAGE_NAME = 'gongxue-app-ui';
export const LEGACY_DOCK_STORAGE_KEY = 'gongxue-route-dock';

export const SETTINGS_STORAGE_NAME = 'gongxue-settings';

function isString(value: unknown): value is string {
  return typeof value === 'string';
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return typeof value === 'object' && value !== null;
}

function isDockTab(value: unknown): value is DockTab {
  return (
    isRecord(value) &&
    typeof value.key === 'string' &&
    value.key.startsWith('/') &&
    typeof value.label === 'string'
  );
}

function readLegacyAuth(): { token: string | null; user: UserInfo | null } {
  const token = localStorage.getItem(LEGACY_TOKEN_KEY);
  const rawUser = localStorage.getItem(LEGACY_USER_KEY);
  let user: UserInfo | null = null;
  if (rawUser !== null) {
    try {
      const parsed: unknown = JSON.parse(rawUser);
      user = isRecord(parsed) ? (parsed as UserInfo) : null;
    } catch {
      user = null;
    }
  }
  return { token, user };
}

interface LegacyAdapter {
  legacyValue: () => string | null;
  clearLegacy: () => void;
}

/** 新 key 无数据时回退到旧 key，首次写入新格式后清理旧 key */
function legacyFallbackStorage(adapter: LegacyAdapter): StateStorage {
  return {
    getItem: (name) => {
      const current = localStorage.getItem(name);
      if (current !== null) return current;
      return adapter.legacyValue();
    },
    setItem: (name, value) => {
      try {
        localStorage.setItem(name, value);
      } catch {
        // 持久化失败不应影响应用运行
      }
      try {
        adapter.clearLegacy();
      } catch {
        // 清理失败不影响应用运行
      }
    },
    removeItem: (name) => {
      try {
        localStorage.removeItem(name);
      } catch {
        // 持久化失败不应影响应用运行
      }
      try {
        adapter.clearLegacy();
      } catch {
        // 清理失败不影响应用运行
      }
    },
  };
}

/** 会话：旧 token/user 两个 key 包装成 version:1 envelope */
function legacyAuthValue(): string | null {
  const { token, user } = readLegacyAuth();
  if (token === null && user === null) return null;
  return JSON.stringify({ state: { token, user }, version: 1 });
}

const authAdapter: LegacyAdapter = {
  legacyValue: legacyAuthValue,
  clearLegacy: () => {
    localStorage.removeItem(LEGACY_TOKEN_KEY);
    localStorage.removeItem(LEGACY_USER_KEY);
  },
};

export const authPersistStorage = createJSONStorage(() =>
  legacyFallbackStorage(authAdapter),
);

/** 权限：旧格式是 permissions 下的裸数组，读取时统一包装成 envelope 以触发 migrate */
const permissionStorage: StateStorage = {
  getItem: (name) => {
    const raw = localStorage.getItem(name);
    if (!raw) return null;
    try {
      const parsed: unknown = JSON.parse(raw);
      if (Array.isArray(parsed)) {
        return JSON.stringify({
          state: { permissions: parsed.filter(isString) },
          version: 1,
        });
      }
      return raw;
    } catch {
      return null;
    }
  },
  setItem: (name, value) => {
    try {
      localStorage.setItem(name, value);
    } catch {
      // 持久化失败不应影响应用运行
    }
  },
  removeItem: (name) => {
    try {
      localStorage.removeItem(name);
    } catch {
      // 持久化失败不应影响应用运行
    }
  },
};

export const permissionPersistStorage = createJSONStorage(() => permissionStorage);

/** 应用 UI：旧 gongxue-route-dock key 包装成 version:1 envelope */
function legacyDockValue(): string | null {
  const legacy = localStorage.getItem(LEGACY_DOCK_STORAGE_KEY);
  if (!legacy) return null;
  try {
    const parsed: unknown = JSON.parse(legacy);
    const routeDockTabs = Array.isArray(parsed) ? parsed.filter(isDockTab) : [];
    return JSON.stringify({ state: { routeDockTabs, sidebarCollapsed: false }, version: 1 });
  } catch {
    return null;
  }
}

const appUiAdapter: LegacyAdapter = {
  legacyValue: legacyDockValue,
  clearLegacy: () => {
    localStorage.removeItem(LEGACY_DOCK_STORAGE_KEY);
  },
};

export const appUiPersistStorage = createJSONStorage(() =>
  legacyFallbackStorage(appUiAdapter),
);

/** 会话状态迁移：读取 v1 envelope 或直接 partial state */
export function migrateAuthState(persisted: unknown, _version: number): UserPersistedState {
  if (isRecord(persisted) && isRecord(persisted.state)) {
    const state = persisted.state as Record<string, unknown>;
    return {
      token: typeof state.token === 'string' ? state.token : null,
      user: isRecord(state.user) ? (state.user as UserInfo) : null,
    };
  }
  const existing = (isRecord(persisted) ? persisted : {}) as Partial<UserPersistedState>;
  return {
    token: existing.token ?? null,
    user: existing.user ?? null,
  };
}

/** 权限状态迁移：兼容 v1 envelope 与裸数组，恢复后一律 fail-closed */
export function migratePermissionState(
  persisted: unknown,
  _version: number,
): PermissionPersistedState {
  if (isRecord(persisted) && isRecord(persisted.state)) {
    const permissions = Array.isArray(persisted.state.permissions)
      ? persisted.state.permissions.filter(isString)
      : [];
    return { permissions };
  }
  if (Array.isArray(persisted)) {
    return { permissions: persisted.filter(isString) };
  }
  const existing = (isRecord(persisted) ? persisted : {}) as Partial<PermissionPersistedState>;
  return {
    permissions: Array.isArray(existing.permissions) ? existing.permissions.filter(isString) : [],
  };
}

/** 应用 UI 状态迁移：读取 v1 envelope 或直接 partial state */
export function migrateAppUiState(persisted: unknown, _version: number): AppPersistedState {
  if (isRecord(persisted) && isRecord(persisted.state)) {
    const state = persisted.state as Record<string, unknown>;
    return {
      routeDockTabs: Array.isArray(state.routeDockTabs)
        ? state.routeDockTabs.filter(isDockTab)
        : [],
      sidebarCollapsed: state.sidebarCollapsed === true,
    };
  }
  const existing = (isRecord(persisted) ? persisted : {}) as Partial<AppPersistedState>;
  return {
    routeDockTabs: Array.isArray(existing.routeDockTabs) ? existing.routeDockTabs : [],
    sidebarCollapsed: existing.sidebarCollapsed ?? false,
  };
}

export type { AppPersistedState, PermissionPersistedState, UserPersistedState };
