// ============================================================
// infrastructure/storage/db-encrypt.ts — 数据库加密持久化
//
// 职责：
//   - 将 sql.js 数据库序列化 → safeStorage 加密 → IPC 写入磁盘
//   - 从磁盘读取 → safeStorage 解密 → 反序列化为 sql.js 可用的 Uint8Array
//   - 降级方案：非 Electron 环境回退 localStorage（仅开发用）
//
// 流程：
//   保存：DB.export() → Uint8Array → base64 → safeStorage.encrypt() → IPC writeFile
//   加载：IPC readFile → base64 → safeStorage.decrypt() → Uint8Array → DB
// ============================================================

import { hasIpc } from '@/shared/utils/bus';
import { exportDatabase } from './db-core';
import { logger } from '@/shared/utils/bus';

/** 数据库文件相对路径（相对于 heixiu-data/） */
const DB_RELATIVE_PATH = 'heixiu.db';

// ---------- 数据编解码 ----------

function uint8ArrayToBase64(data: Uint8Array): string {
  let binary = '';
  for (let i = 0; i < data.byteLength; i++) {
    binary += String.fromCharCode(data[i]);
  }
  return btoa(binary);
}

function base64ToUint8Array(b64: string): Uint8Array {
  const binary = atob(b64);
  const bytes = new Uint8Array(binary.length);
  for (let i = 0; i < binary.length; i++) {
    bytes[i] = binary.charCodeAt(i);
  }
  return bytes;
}

// ---------- 公开 API ----------

/** 保存数据库到磁盘（加密 + IPC 写文件） */
export async function saveDatabase(): Promise<boolean> {
  const data = exportDatabase();
  if (!data) {
    console.warn('[storage] saveDatabase：exportDatabase 返回 null（数据库未打开？）');
    return false;
  }
  console.log(`[storage] saveDatabase：导出 ${data.byteLength} bytes`);

  const base64 = uint8ArrayToBase64(data);
  console.log(`[storage] saveDatabase：Base64 编码后 ${base64.length} chars`);

  // Electron 环境：加密后写磁盘
  if (hasIpc() && window.fileStorage && window.safeStorage) {
    console.log('[storage] saveDatabase：Electron 环境，准备加密...');
    try {
      const encrypted = await window.safeStorage.encrypt(base64);
      if (!encrypted) {
        console.warn('[storage] saveDatabase：safeStorage.encrypt 返回 null');
        return false;
      }
      console.log(`[storage] saveDatabase：加密后 ${encrypted.length} chars，准备写入磁盘...`);
      const result = await window.fileStorage.writeFile(DB_RELATIVE_PATH, encrypted, 'base64');
      console.log(`[storage] saveDatabase：写入结果 = ${result}`);
      return result !== null;
    } catch (err) {
      console.error('[storage] saveDatabase 异常：', err);
      logger.error('storage', '数据库加密保存失败', err instanceof Error ? err : undefined);
      return false;
    }
  }

  // 降级：localStorage 明文（仅开发用）
  console.log('[storage] saveDatabase：非 Electron 环境，使用 localStorage 降级');
  try {
    localStorage.setItem('ele-heixiu-db', base64);
    return true;
  } catch {
    return false;
  }
}

/** 从磁盘加载数据库（IPC 读文件 + 解密） */
export async function loadDatabase(): Promise<Uint8Array | undefined> {
  // Electron 环境：读文件 + 解密
  if (hasIpc() && window.fileStorage && window.safeStorage) {
    console.log('[storage] loadDatabase：Electron 环境，读取磁盘...');
    try {
      const encrypted = await window.fileStorage.readFile(DB_RELATIVE_PATH);
      if (!encrypted) {
        console.log('[storage] loadDatabase：磁盘文件不存在（首次启动）');
        return undefined;
      }
      console.log(`[storage] loadDatabase：读取加密数据 ${encrypted.length} chars，准备解密...`);
      const base64 = await window.safeStorage.decrypt(encrypted);
      if (!base64) {
        console.warn('[storage] loadDatabase：解密失败');
        return undefined;
      }
      console.log(`[storage] loadDatabase：解密后 ${base64.length} chars`);
      return base64ToUint8Array(base64);
    } catch (err) {
      console.warn('[storage] loadDatabase 异常：', err);
      logger.warn('storage', '数据库解密加载失败', err instanceof Error ? err : undefined);
      return undefined;
    }
  }

  // 降级：localStorage 明文
  console.log('[storage] loadDatabase：非 Electron 环境，尝试 localStorage...');
  try {
    const raw = localStorage.getItem('ele-heixiu-db');
    if (!raw) {
      console.log('[storage] loadDatabase：localStorage 无数据');
      return undefined;
    }
    console.log(`[storage] loadDatabase：localStorage 有数据 ${raw.length} chars`);
    return base64ToUint8Array(raw);
  } catch {
    return undefined;
  }
}
