import{getUpdates as P}from"../api/api.js";import{WeixinConfigManager as k}from"../api/config-cache.js";import{SESSION_EXPIRED_ERRCODE as w,pauseSession as F,getRemainingPauseMs as L}from"../api/session-guard.js";import{processOneMessage as O}from"../messaging/process-message.js";import{waitForWeixinRuntime as T}from"../runtime.js";import{getSyncBufFilePath as C,loadGetUpdatesBuf as B,saveGetUpdatesBuf as I}from"../storage/sync-buf.js";import{logger as W}from"../util/logger.js";import{redactBody as D}from"../util/redact.js";const S=35e3,o=3,N=3e4,G=2e3;async function Z(a){const{baseUrl:s,cdnBaseUrl:_,token:d,accountId:i,config:M,abortSignal:r,longPollTimeoutMs:U,setStatus:x}=a,p=a.runtime?.log??(()=>{}),g=a.runtime?.error??(e=>p(e)),t=W.withAccount(i);t.info("waiting for Weixin runtime...");let b;try{b=(await T()).channel,t.info(`Weixin runtime acquired, channelRuntime type: ${typeof b}`)}catch(e){throw t.error(`waitForWeixinRuntime() failed: ${String(e)}`),e}p(`weixin monitor started (${s}, account=${i})`),t.info(`Monitor started: baseUrl=${s} timeoutMs=${U??S}`);const $=C(i);t.debug(`syncFilePath: ${$}`);const h=B($);let u=h??"";h?(p(`[weixin] resuming from previous sync buf (${u.length} bytes)`),t.debug(`Using previous get_updates_buf (${u.length} bytes)`)):(p("[weixin] no previous sync buf, starting fresh"),t.info("No previous get_updates_buf found, starting fresh"));const y=new k({baseUrl:s,token:d},p);let m=U??S,n=0;for(;!r?.aborted;)try{t.debug(`getUpdates: get_updates_buf=${u.substring(0,50)}..., timeoutMs=${m}`);const e=await P({baseUrl:s,token:d,get_updates_buf:u,timeoutMs:m,abortSignal:r});if(t.debug(`getUpdates response: ret=${e.ret}, msgs=${e.msgs?.length??0}, get_updates_buf_length=${e.get_updates_buf?.length??0}`),e.longpolling_timeout_ms!=null&&e.longpolling_timeout_ms>0&&(m=e.longpolling_timeout_ms,t.debug(`Updated next poll timeout: ${m}ms`)),e.ret!==void 0&&e.ret!==0||e.errcode!==void 0&&e.errcode!==0){if(e.errcode===w||e.ret===w){F(i);const l=L(i);g(`weixin getUpdates: session expired (errcode ${w}), pausing bot for ${Math.ceil(l/6e4)} min`),t.error(`getUpdates: session expired (errcode=${e.errcode} ret=${e.ret}), pausing all requests for ${Math.ceil(l/6e4)} min`),n=0,await f(l,r);continue}n+=1,g(`weixin getUpdates failed: ret=${e.ret} errcode=${e.errcode} errmsg=${e.errmsg??""} (${n}/${o})`),t.error(`getUpdates failed: ret=${e.ret} errcode=${e.errcode} errmsg=${e.errmsg} response=${D(JSON.stringify(e))}`),n>=o?(g(`weixin getUpdates: ${o} consecutive failures, backing off 30s`),t.error(`getUpdates: ${o} consecutive failures, backing off 30s`),n=0,await f(N,r)):await f(G,r);continue}n=0,x?.({accountId:i,lastEventAt:Date.now()}),e.get_updates_buf!=null&&e.get_updates_buf!==""&&(r?.aborted||I($,e.get_updates_buf),u=e.get_updates_buf,t.debug(`Saved new get_updates_buf (${u.length} bytes)`));const E=e.msgs??[];for(const c of E){t.info(`inbound message: from=${c.from_user_id} types=${c.item_list?.map(R=>R.type).join(",")??"none"}`);const l=Date.now();x?.({accountId:i,lastEventAt:l,lastInboundAt:l});const v=c.from_user_id??"",A=await y.getForUser(v,c.context_token);await O(c,{accountId:i,config:M,channelRuntime:b,baseUrl:s,cdnBaseUrl:_,token:d,typingTicket:A.typingTicket,log:a.runtime?.log??(()=>{}),errLog:g})}}catch(e){if(r?.aborted){t.info("Monitor stopped (aborted)");return}n+=1,g(`weixin getUpdates error (${n}/${o}): ${String(e)}`),t.error(`getUpdates error: ${String(e)}, stack=${e.stack}`),n>=o?(g(`weixin getUpdates: ${o} consecutive failures, backing off 30s`),t.error(`getUpdates: ${o} consecutive failures, backing off 30s`),n=0,await f(3e4,r)):await f(2e3,r)}t.info("Monitor ended")}function f(a,s){return new Promise((_,d)=>{const i=setTimeout(_,a);s?.addEventListener("abort",()=>{clearTimeout(i),d(new Error("aborted"))},{once:!0})})}export{Z as monitorWeixinProvider};
