(function () {
  const config = (typeof require === 'function')
    ? require('./config.js')
    : (typeof window !== 'undefined' ? window.appConfig : null);
  const datesModule = (typeof require === 'function')
    ? require('./dates.js')
    : (typeof window !== 'undefined' ? window.dates : null);
  const { getWeekDates } = datesModule;

  function buildQuery(params) {
    const search = new URLSearchParams();
    for (const [key, value] of Object.entries(params)) {
      if (value === undefined || value === null || value === '') continue;
      search.append(key, value);
    }
    const qs = search.toString();
    return qs ? `?${qs}` : '';
  }

  function createClient(options = {}) {
    const fetchImpl = options.fetch || (typeof fetch !== 'undefined' ? fetch : null);
    if (!fetchImpl) throw new Error('fetch implementation is required');

    let token = null;
    let tokenPromise = null;

    function setToken(value) {
      token = value;
    }

    function getToken() {
      return token;
    }

    async function ensureToken() {
      if (token) return token;
      if (!tokenPromise) {
        tokenPromise = (async () => {
          const url = `${config.baseUrl}/getAccessToken?appId=${encodeURIComponent(config.appId)}&appSecret=${encodeURIComponent(config.appSecret)}`;
          const res = await fetchImpl(url, { method: 'GET' });
          const data = await res.json();
          if (!res.ok || !data || data.code !== '0000' || !data.data || !data.data.token) {
            tokenPromise = null;
            throw new Error('获取 Token 失败');
          }
          token = data.data.token;
          tokenPromise = null;
          return token;
        })();
      }
      return tokenPromise;
    }

    async function request(path, { method = 'GET', query, body, retry = true } = {}) {
      const url = `${config.baseUrl}${path}${buildQuery(query || {})}`;
      const headers = { 'Content-Type': 'application/json' };
      const tk = await ensureToken();
      headers.Authorization = `Bearer ${tk}`;
      const options = { method, headers };
      if (body !== undefined) options.body = JSON.stringify(body);

      const res = await fetchImpl(url, options);
      if (res.status === 401 || res.status === 403) {
        if (retry) {
          token = null;
          return request(path, { method, query, body, retry: false });
        }
        throw new Error('认证失败，请重新登录');
      }
      const text = await res.text();
      let json = {};
      if (text) {
        try { json = JSON.parse(text); } catch (err) { json = {}; }
      } else {
        try { json = await res.json(); } catch (err) { json = {}; }
      }
      if (!res.ok) {
        throw new Error((json && json.message) || `请求失败 (${res.status})`);
      }
      if (json && json.code !== undefined && json.code !== '0000') {
        throw new Error((json && (json.message || json.data && json.data.msg)) || '业务错误');
      }
      return json;
    }

    async function listPage(table, { pageNum = 1, pageSize = config.pageSize, ...rest } = {}) {
      const filters = {};
      for (const [key, value] of Object.entries(rest)) {
        if (value === undefined || value === null || value === '') continue;
        const stringValue = String(value);
        filters[key] = stringValue.includes('.') ? stringValue : `eq.${stringValue}`;
      }
      const json = await request(`/api/sqlite/course/${table}`, {
        query: { pageNum, pageSize, ...filters }
      });
      const payload = (json && json.data) || {};
      return {
        records: payload.records || [],
        total: payload.total || 0
      };
    }

    async function listAll(table, filters) {
      const records = [];
      let pageNum = 1;
      while (true) {
        const { records: chunk, total } = await listPage(table, { ...filters, pageNum });
        records.push(...chunk);
        if (records.length >= total || chunk.length === 0) break;
        pageNum += 1;
        if (pageNum > 200) break; // safety guard
      }
      return records;
    }

    async function listSchedulesForWeek(weekStart, filters = {}) {
      const dates = getWeekDates(weekStart);
      const results = await Promise.all(dates.map(async (date) => {
        try {
          const { records } = await listPage('course_schedules', {
            ...filters,
            schedule_date: `eq.${date}`
          });
          return { date, records };
        } catch (err) {
          return { date, records: [], error: err };
        }
      }));
      const records = [];
      for (const { date, records: chunk, error } of results) {
        if (error) continue;
        for (const r of chunk) records.push(r);
      }
      return records;
    }

    async function createSchedule(payload) {
      const json = await request('/api/sqlite/course/course_schedules', {
        method: 'POST',
        body: [payload]
      });
      return json.data;
    }

    async function updateSchedule(payload) {
      const json = await request('/api/sqlite/course/course_schedules', {
        method: 'PATCH',
        body: [payload]
      });
      return json.data;
    }

    async function deleteSchedule(id) {
      const json = await request('/api/sqlite/course/course_schedules', {
        method: 'DELETE',
        query: { id }
      });
      return json.data;
    }

    async function listTeachers(name) {
      const filters = {};
      const trimmed = typeof name === 'string' ? name.trim() : '';
      if (trimmed) filters.name = `like.*${trimmed}*`;
      return listAll('teachers', filters);
    }

    async function listClasses(name) {
      const filters = {};
      const trimmed = typeof name === 'string' ? name.trim() : '';
      if (trimmed) filters.name = `like.*${trimmed}*`;
      return listAll('classes', filters);
    }

    async function createClass(payload) {
      const json = await request('/api/sqlite/course/classes', {
        method: 'POST',
        body: [payload]
      });
      return json.data;
    }

    async function updateClass(payload) {
      const json = await request('/api/sqlite/course/classes', {
        method: 'PATCH',
        body: [payload]
      });
      return json.data;
    }

    async function deleteClass(id) {
      const json = await request('/api/sqlite/course/classes', {
        method: 'DELETE',
        query: { id }
      });
      return json.data;
    }

    async function findClassReferences(id) {
      const schedulesResult = await listPage('course_schedules', { class_id: id, pageSize: 1 });
      return { schedules: { total: schedulesResult.total } };
    }

    async function listClassrooms(name) {
      const filters = {};
      const trimmed = typeof name === 'string' ? name.trim() : '';
      if (trimmed) filters.name = `like.*${trimmed}*`;
      return listAll('classrooms', filters);
    }

    async function createClassroom(payload) {
      const json = await request('/api/sqlite/course/classrooms', {
        method: 'POST',
        body: [payload]
      });
      return json.data;
    }

    async function createTeacher(payload) {
      const json = await request('/api/sqlite/course/teachers', {
        method: 'POST',
        body: [payload]
      });
      return json.data;
    }

    async function deleteTeacher(id) {
      const json = await request('/api/sqlite/course/teachers', {
        method: 'DELETE',
        query: { id }
      });
      return json.data;
    }

    async function findTeacherReferences(id) {
      const [classesResult, schedulesResult] = await Promise.allSettled([
        listPage('classes', { teacher_id: id, pageSize: 1 }),
        listPage('course_schedules', { teacher_id: id, pageSize: 1 })
      ]);
      if (classesResult.status === 'rejected' || schedulesResult.status === 'rejected') {
        const reason = (classesResult.status === 'rejected' && classesResult.reason)
          || (schedulesResult.status === 'rejected' && schedulesResult.reason)
          || new Error('引用检查失败');
        throw reason;
      }
      return {
        classes: { total: classesResult.value.total },
        schedules: { total: schedulesResult.value.total }
      };
    }

    async function deleteClassroom(id) {
      const json = await request('/api/sqlite/course/classrooms', {
        method: 'DELETE',
        query: { id }
      });
      return json.data;
    }

    async function findClassroomReferences(id) {
      const [classesResult, schedulesResult] = await Promise.allSettled([
        listPage('classes', { classroom_id: id, pageSize: 1 }),
        listPage('course_schedules', { classroom_id: id, pageSize: 1 })
      ]);
      if (classesResult.status === 'rejected' || schedulesResult.status === 'rejected') {
        const reason = (classesResult.status === 'rejected' && classesResult.reason)
          || (schedulesResult.status === 'rejected' && schedulesResult.reason)
          || new Error('引用检查失败');
        throw reason;
      }
      return {
        classes: { total: classesResult.value.total },
        schedules: { total: schedulesResult.value.total }
      };
    }

    return {
      fetchToken: ensureToken,
      listAll,
      listSchedulesForWeek,
      createSchedule,
      updateSchedule,
      deleteSchedule,
      listTeachers,
      createTeacher,
      deleteTeacher,
      findTeacherReferences,
      listClasses,
      createClass,
      updateClass,
      deleteClass,
      findClassReferences,
      listClassrooms,
      createClassroom,
      deleteClassroom,
      findClassroomReferences,
      getToken,
      setToken
    };
  }

  const exports_ = { createClient };

  if (typeof module !== 'undefined' && module.exports) {
    module.exports = exports_;
  }

  if (typeof window !== 'undefined') {
    window.api = exports_;
  }
})();