"use client" import {useEffect,useRef,useState} from "react" import {normalizeAlertsConfig,type PutRulesBody} from "@mmapp/contracts/alerts" import {can} from "@/lib/auth" import {ApiClientError} from "@/shared/api/http-client" import {saveAlertRules} from "@/shared/api/alerts" const pending=new Set() const key=(source:string)=>"mm:alerts-rules-pending:"+source function unresolved(source:string){try{return pending.has(source)||sessionStorage.getItem(key(source))==="true"}catch{return pending.has(source)}} function checkpoint(source:string,value:boolean){if(value)pending.add(source);else pending.delete(source);try{if(value)sessionStorage.setItem(key(source),"true");else sessionStorage.removeItem(key(source))}catch{/* The memory guard survives section navigation. */}} export function useAlertsConfigWrite(base:string,live:boolean,available:boolean,expectedRevision:string|null,onBegin:()=>boolean,onEnd:()=>void){ const source=JSON.stringify([live,base]) const [busy,setBusy]=useState(false),[error,setError]=useState(null),[outcome,setOutcome]=useState(null),[unknown,setUnknown]=useState(false),[ready,setReady]=useState(false) const active=useRef(true),lock=useRef(false),controller=useRef(null) useEffect(()=>{active.current=true;queueMicrotask(()=>{if(active.current){setReady(true);setUnknown(unresolved(source))}});return()=>{active.current=false;controller.current?.abort()}},[source]) const enabled=ready&&live&&available&&!!expectedRevision&&can("mm:alerts:write") async function save(payload:PutRulesBody){ if(!enabled||lock.current||unknown||!active.current||!can("mm:alerts:write"))return null let normalized:ReturnType try{normalized=normalizeAlertsConfig(payload)}catch(e){setError(e instanceof Error?e.message:"Проверьте параметры правил");return null} if(!onBegin())return null lock.current=true;controller.current=new AbortController();setBusy(true);setError(null);setOutcome(null);checkpoint(source,true);setUnknown(true) const current=()=>active.current&&can("mm:alerts:write") try{ const receipt=await saveAlertRules(base,normalized,{signal:controller.current.signal,expectedRevision:expectedRevision??undefined});if(!current())return null checkpoint(source,false);setUnknown(false);setOutcome("Правила и группы сохранены в БД");return receipt }catch(e){ const rejected=e instanceof ApiClientError&&[400,401,403,409,412,422,428].includes(e.status) if(rejected&¤t())checkpoint(source,false) if(current()){setUnknown(!rejected);setError(e instanceof Error?e.message:"Результат сохранения правил не получен")};return null }finally{lock.current=false;controller.current=null;if(active.current){setBusy(false);onEnd()}} } function review(){if(!enabled||busy)return;checkpoint(source,false);setUnknown(false)} return {save,busy,error,outcome,unknown,enabled,review} }