import crypto from 'node:crypto';
import fs from 'node:fs';
import path from 'node:path';

let DB_DIR = '';
let USERS_FILE = '';
let PAGES_DIR = '';
function initPaths(dataDir) {
  DB_DIR = dataDir;
  USERS_FILE = path.join(DB_DIR, 'users.json');
  PAGES_DIR = path.join(DB_DIR, 'pages');
}

function ensureDb() {
  fs.mkdirSync(DB_DIR, { recursive: true });
  fs.mkdirSync(PAGES_DIR, { recursive: true });
  if (!fs.existsSync(USERS_FILE)) {
    fs.writeFileSync(USERS_FILE, JSON.stringify({ users: [] }, null, 2), 'utf-8');
  }
}

function readUsers() {
  ensureDb();
  return JSON.parse(fs.readFileSync(USERS_FILE, 'utf-8'));
}

function writeUsers(data) {
  ensureDb();
  fs.writeFileSync(USERS_FILE, JSON.stringify(data, null, 2), 'utf-8');
}

function safeEqual(a, b) {
  const ba = Buffer.from(a);
  const bb = Buffer.from(b);
  return ba.length === bb.length && crypto.timingSafeEqual(ba, bb);
}

export function createWikiAuth(dataDir) {
  initPaths(dataDir);
  ensureDb();

  const sessions = new Map();
  const COOKIE_NAME = 'wiki_session';

  function hashPassword(password, salt) {
    return crypto.pbkdf2Sync(password, salt, 100000, 64, 'sha512').toString('hex');
  }

  function register(username, password, displayName) {
    const db = readUsers();
    if (db.users.find(u => u.username === username)) {
      return { ok: false, message: '用户名已存在' };
    }
    const salt = crypto.randomBytes(16).toString('hex');
    const hashed = hashPassword(password, salt);
    const user = {
      id: crypto.randomUUID(),
      username,
      displayName: displayName || username,
      salt,
      hashedPassword: hashed,
      createdAt: Date.now(),
    };
    db.users.push(user);
    writeUsers(db);
    return { ok: true, user: { id: user.id, username: user.username, displayName: user.displayName } };
  }

  function login(username, password) {
    const db = readUsers();
    const user = db.users.find(u => u.username === username);
    if (!user) return { ok: false, message: '用户名或密码错误' };
    const hashed = hashPassword(password, user.salt);
    if (!safeEqual(hashed, user.hashedPassword)) {
      return { ok: false, message: '用户名或密码错误' };
    }
    const token = crypto.randomBytes(32).toString('base64url');
    sessions.set(token, { userId: user.id, username: user.username, expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000 });
    return { ok: true, token, user: { id: user.id, username: user.username, displayName: user.displayName } };
  }

  function verify(token) {
    if (!token) return null;
    const session = sessions.get(token);
    if (!session || session.expiresAt < Date.now()) {
      sessions.delete(token);
      return null;
    }
    // extend session
    session.expiresAt = Date.now() + 7 * 24 * 60 * 60 * 1000;
    return session;
  }

  function revoke(token) {
    sessions.delete(token);
  }

  function getUser(username) {
    const db = readUsers();
    const user = db.users.find(u => u.username === username);
    if (!user) return null;
    return { id: user.id, username: user.username, displayName: user.displayName, createdAt: user.createdAt };
  }

  function getAllUsers() {
    const db = readUsers();
    return db.users.map(u => ({ id: u.id, username: u.username, displayName: u.displayName, createdAt: u.createdAt }));
  }

  // Page CRUD
  function listPages(username) {
    ensureDb();
    const userPagesDir = path.join(PAGES_DIR, username);
    if (!fs.existsSync(userPagesDir)) return [];
    return fs.readdirSync(userPagesDir)
      .filter(f => f.endsWith('.json'))
      .map(f => {
        const data = JSON.parse(fs.readFileSync(path.join(userPagesDir, f), 'utf-8'));
        return {
          id: data.id,
          title: data.title,
          slug: data.slug,
          updatedAt: data.updatedAt,
          createdAt: data.createdAt,
          tags: data.tags || [],
        };
      })
      .sort((a, b) => b.updatedAt - a.updatedAt);
  }

  function getPage(username, slug) {
    ensureDb();
    const filePath = path.join(PAGES_DIR, username, `${slug}.json`);
    if (!fs.existsSync(filePath)) return null;
    return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
  }

  function savePage(username, slug, title, content, tags) {
    ensureDb();
    const userPagesDir = path.join(PAGES_DIR, username);
    fs.mkdirSync(userPagesDir, { recursive: true });
    const filePath = path.join(userPagesDir, `${slug}.json`);
    const existing = fs.existsSync(filePath) ? JSON.parse(fs.readFileSync(filePath, 'utf-8')) : null;
    const page = {
      id: existing?.id || crypto.randomUUID(),
      slug,
      title: title || slug,
      content: content || '',
      tags: tags || [],
      username,
      createdAt: existing?.createdAt || Date.now(),
      updatedAt: Date.now(),
    };
    fs.writeFileSync(filePath, JSON.stringify(page, null, 2), 'utf-8');
    return page;
  }

  function deletePage(username, slug) {
    ensureDb();
    const filePath = path.join(PAGES_DIR, username, `${slug}.json`);
    if (fs.existsSync(filePath)) {
      fs.unlinkSync(filePath);
      return true;
    }
    return false;
  }

  function searchPages(username, query) {
    const pages = listPages(username);
    const q = query.toLowerCase();
    return pages.filter(p =>
      p.title.toLowerCase().includes(q) ||
      p.tags.some(t => t.toLowerCase().includes(q))
    );
  }

  return {
    COOKIE_NAME,
    register,
    login,
    verify,
    revoke,
    getUser,
    getAllUsers,
    listPages,
    getPage,
    savePage,
    deletePage,
    searchPages,
  };
}
