/**
 * VBase - Scoped RBAC 权限管理客户端
 * 对应后端: github.com/veypi/vigo/contrib/auth.Auth 接口
 *
 * Token 基于 HttpOnly Cookie 管理，JS 不可读，防沙箱泄露。
 * 非浏览器客户端仍可通过 Authorization header 传递 token。
 */

// 权限等级常量 (与后端一致)
export const Level = {
  None: 0,
  Create: 1,      // 001 创建 (奇数层)
  Read: 2,        // 010 读取 (偶数层)
  Write: 4,       // 100 写入 (偶数层)
  ReadWrite: 6,   // 110 读写 (偶数层)
  Admin: 7,       // 111 管理员 (完全控制)
};

const REFRESH_INTERVAL = 12 * 60 * 1000; // 12 分钟（access_token 15min 过期）

class VBase {
  constructor(baseURL, login_page, users = {}) {
    if (!baseURL) baseURL = window.location.origin;
    if (baseURL === '' || baseURL === '/') baseURL = window.location.origin;

    this.baseURL = baseURL;
    this.login_page = login_page || (baseURL + '/login');
    this.userKey = 'vbase_user';
    this.refreshTimer = null;
    this.users = users;
    this._user = null;

    try {
      const cached = JSON.parse(localStorage.getItem(this.userKey));
      if (cached) {
        this._user = cached;
        this._cachePublicUser(cached);
      }
    } catch (e) { }

    this._pendingUserIDs = new Set();
    this._loadingUserIDs = new Set();
    this._resolvedUserIDs = new Set();
    this._pendingUserFlush = null;

    // 初始化鉴权：有用户缓存就验证 + 定时刷新
    if (this._user) {
      this._ensureAuth();
    }
  }

  async _ensureAuth() {
    const now = Date.now();
    const lastRefresh = parseInt(localStorage.getItem('vbase_last_refresh'), 10) || 0;

    // 超过 12 分钟没刷新，先刷新再拉用户
    if (now - lastRefresh > REFRESH_INTERVAL) {
      const ok = await this.refresh();
      if (!ok) {
        this.clear();
        return;
      }
    }

    // 无用户信息或刷新后重新拉
    try {
      await this.fetchUser();
    } catch (e) {
      this.clear();
      return;
    }

    // 启动定时刷新
    this._startRefreshTimer();
  }

  _startRefreshTimer() {
    this._stopRefreshTimer();
    this.refreshTimer = setInterval(() => {
      this.refresh().then(ok => {
        if (!ok) this.clear();
      });
    }, REFRESH_INTERVAL);
  }

  _stopRefreshTimer() {
    if (this.refreshTimer) {
      clearInterval(this.refreshTimer);
      this.refreshTimer = null;
    }
  }

  // ========== Getters / Setters ==========

  get user() { return this._user; }

  set user(val) {
    this._user = val;
    if (val) {
      localStorage.setItem(this.userKey, JSON.stringify(val));
    } else {
      localStorage.removeItem(this.userKey);
      localStorage.removeItem('vbase_last_refresh');
    }
    this._cachePublicUser(val);
  }

  _touchRefresh() {
    localStorage.setItem('vbase_last_refresh', Date.now().toString());
  }

  // ========== API 请求 ==========

  async request(method, path, data = null, headers = {}) {
    const url = `${this.baseURL}${path}`;
    const config = {
      method,
      headers: {
        'Content-Type': 'application/json',
        ...headers,
      },
    };
    if (data) config.body = JSON.stringify(data);

    const response = await fetch(url, config);
    const resData = await response.json();

    if (!response.ok) {
      const error = new Error(resData.message || `Request failed: ${response.status}`);
      Object.assign(error, resData);
      throw error;
    }

    if (resData.code && resData.code !== 200) {
      const error = new Error(resData.message || 'API Error');
      Object.assign(error, resData);
      throw error;
    }

    return resData.data || resData;
  }

  // ========== 认证 ==========

  /** 登录成功后初始化鉴权状态（密码登录之外的方式：验证码、OAuth、注册后自动登录等） */
  async onAuthSuccess(user) {
    this._touchRefresh();
    this.user = user;
    await this.fetchUser();
    this._startRefreshTimer();
  }

  /** 用户名密码登录 */
  async login(username, password) {
    const data = await this.request('POST', '/api/auth/login', { username, password });
    if (data.user) {
      await this.onAuthSuccess(data.user);
      return true;
    }
    return false;
  }

  /** OAuth 回调 */
  async oauthCallback(provider, code, state) {
    const data = await this.request('GET', `/api/auth/callback/${provider}?code=${code}&state=${state}`);
    if (data.user) await this.onAuthSuccess(data.user);
    return data;
  }

  /** 绑定已有账号 */
  async bindAccount(tempToken, username, password) {
    const data = await this.request('POST', '/api/auth/bind', {
      temp_token: tempToken, username, password,
    });
    if (data.user) await this.onAuthSuccess(data.user);
    return data;
  }

  /** 绑定并注册 */
  async bindRegister(tempToken, username, email) {
    const data = await this.request('POST', '/api/auth/bind-register', {
      temp_token: tempToken, username, email,
    });
    if (data.user) await this.onAuthSuccess(data.user);
    return data;
  }

  /** 登出 */
  async logout(redirect) {
    try {
      await this.request('POST', '/api/auth/logout');
    } catch (e) {
      console.warn('Logout API failed', e);
    } finally {
      this.clear();
      const redirectUrl = redirect || window.location.pathname + window.location.search;
      location.href = this.login_page + '?redirect=' + encodeURIComponent(redirectUrl);
    }
  }

  /** Token 刷新 */
  async refresh() {
    try {
      await this.request('POST', '/api/auth/refresh', {});
      this._touchRefresh();
      return true;
    } catch (e) {
      return false;
    }
  }

  /** 获取当前用户信息及权限 */
  async fetchUser() {
    try {
      const user = await this.request('GET', '/api/auth/me');
      this.user = user;
      return user;
    } catch (e) {
      this.clear();
      throw e;
    }
  }

  /** 清除登录状态 */
  clear() {
    this._stopRefreshTimer();
    this.user = null;
    for (const id of Object.keys(this.users)) {
      delete this.users[id];
    }
    this._pendingUserIDs.clear();
    this._loadingUserIDs.clear();
    this._resolvedUserIDs.clear();
    this._pendingUserFlush = null;
  }

  // ========== 用户 ==========

  User(id) {
    if (!id) return {};

    if (!this.users[id]) {
      this.users[id] = {};
    }

    if (!this._resolvedUserIDs.has(id) && !this._loadingUserIDs.has(id)) {
      this._pendingUserIDs.add(id);
      if (!this._pendingUserFlush) {
        this._pendingUserFlush = Promise.resolve().then(() => this._flushUserRequests());
      }
    }

    return this.users[id];
  }

  // ========== 权限检查 ==========

  Perm(code, level = Level.Read) {
    if (!this.user) return false;
    if (!code) return true;

    const perms = this.user.permissions || [];
    return this._checkPermissionLevel(perms, code, level);
  }

  PermCreate(code) { return this.Perm(code, Level.Create); }
  PermRead(code) { return this.Perm(code, Level.Read); }
  PermWrite(code) { return this.Perm(code, Level.Write); }
  PermAdmin(code) { return this.Perm(code, Level.Admin); }

  // ========== 内部方法 ==========

  _checkPermissionLevel(perms, targetPermID, requiredLevel) {
    for (const p of perms) {
      const permID = p.permission_id || p;
      const permLevel = p.level !== undefined ? p.level : Level.Read;

      if (permLevel === Level.Admin) {
        if (permID === '*' || targetPermID.startsWith(permID + ':') || permID === targetPermID) {
          return true;
        }
      }

      if (permLevel >= requiredLevel) {
        if (permID === targetPermID) {
          return true;
        }
      }
    }
    return false;
  }

  _cachePublicUser(user) {
    if (!user?.id) return;

    const cached = {
      ...user,
      name: user.name || user.nickname || user.username || '',
      icon: user.icon || user.avatar || '',
      avatar: user.avatar || user.icon || '',
    };
    if (!this.users[cached.id]) {
      this.users[cached.id] = {};
    }
    Object.assign(this.users[cached.id], cached);
    this._resolvedUserIDs.add(cached.id);
    this._loadingUserIDs.delete(cached.id);
  }

  async _flushUserRequests() {
    const ids = [...this._pendingUserIDs].filter(Boolean);
    this._pendingUserIDs.clear();
    this._pendingUserFlush = null;
    if (ids.length === 0) return;

    for (const id of ids) {
      this._loadingUserIDs.add(id);
    }

    try {
      const res = await this.request('POST', '/api/auth/users', { ids });
      const items = Array.isArray(res?.items) ? res.items : [];
      const found = new Set();

      for (const item of items) {
        this._cachePublicUser(item);
        found.add(item.id);
      }

      for (const id of ids) {
        this._loadingUserIDs.delete(id);
        if (!found.has(id)) {
          this._resolvedUserIDs.add(id);
        }
      }
    } catch (error) {
      for (const id of ids) {
        this._loadingUserIDs.delete(id);
      }
      console.warn('VBase: batch fetch users failed', error);
    }
  }
}

export default VBase;
