(function () {
    "use strict";
    var config = window.h4bsCalendarData || {};
    var root = document.querySelector("[data-h4bs-calendar-admin]");
    if (!root) return;
    function normalizeWorkspace(value) {
        var next = JSON.parse(JSON.stringify(value || {}));
        if (!next.overrides || Array.isArray(next.overrides)) next.overrides = {};
        ["sources", "source_events", "local_events"].forEach(function (key) { if (!Array.isArray(next[key])) next[key] = []; });
        return next;
    }
    var state = normalizeWorkspace(config.workspace || {});
    var history = [];
    var future = [];
    var dirty = false;
    var saving = false;
    var pendingRequestId = "";
    var pendingRequestPayload = "";
    var editing = null;
    var eventList = root.querySelector("[data-calendar-event-list]");
    var sourceList = root.querySelector("[data-calendar-source-list]");
    var saveState = root.querySelector("[data-h4bs-calendar-save-state]");
    var saveButton = root.querySelector("[data-h4bs-calendar-save]");
    var dialog = root.querySelector("[data-calendar-editor]");
    var editorFields = root.querySelector("[data-calendar-editor-fields]");
    var editorStatus = root.querySelector("[data-calendar-editor-status]");
    var editorSubmit = root.querySelector("[data-calendar-editor-form] button[type=submit]");
    var eventLimit = 15;
    var moreEvents = document.createElement("button"); moreEvents.type="button"; moreEvents.className="button"; moreEvents.textContent="Show more events"; eventList.after(moreEvents);

    function clone(value) { return JSON.parse(JSON.stringify(value)); }
    function uuid(){if(window.crypto&&typeof window.crypto.randomUUID==="function")return window.crypto.randomUUID();return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(character){var random=Math.random()*16|0;return (character==="x"?random:(random&3|8)).toString(16);});}
    function setSaveState(kind, message) {
        if (saveState) {
            saveState.textContent = message;
            saveState.dataset.state = kind;
            saveState.classList.toggle("h4bs-calendar-error", kind === "error");
        }
        if (saveButton) {
            saveButton.disabled = saving || !dirty;
            saveButton.classList.toggle("button-primary", dirty);
            saveButton.setAttribute("aria-disabled", saveButton.disabled ? "true" : "false");
        }
    }
    function syncHistoryButtons(){var undo=root.querySelector("[data-calendar-undo]");var redo=root.querySelector("[data-calendar-redo]");if(undo)undo.disabled=!history.length;if(redo)redo.disabled=!future.length;}
    function snapshot() { history.push(clone(state)); if (history.length > 50) history.shift(); future = []; syncHistoryButtons(); }
    function markDirty(message) { dirty = true; setSaveState("dirty", message || "Unsaved calendar changes"); }
    function allEvents() { return (state.source_events || []).concat(state.local_events || []); }
    function effective(event) {
        var override = (state.overrides || {})[event.id] || {};
        return Object.assign({}, event, {
            title: override.title || event.title,
            description: override.description || event.description,
            category: override.category || event.category,
            badge: override.badge || event.badge,
            event_status: override.event_status || event.event_status,
            timezone: override.timezone || event.timezone,
            venue_name: override.venue_name || event.venue_name,
            street_address: override.street_address || event.street_address,
            address_locality: override.address_locality || event.address_locality,
            address_region: override.address_region || event.address_region,
            postal_code: override.postal_code || event.postal_code,
            address_country: override.address_country || event.address_country,
            ticket_url: override.ticket_url || event.ticket_url,
            offer_price: override.offer_price === "" ? event.offer_price : override.offer_price,
            offer_currency: override.offer_currency || event.offer_currency,
            hidden: !!override.hidden,
        });
    }
    function esc(value) { var el = document.createElement("div"); el.textContent = String(value || ""); return el.innerHTML; }
    function renderEvents() {
        var query = String(root.querySelector("[data-calendar-search]").value || "").toLowerCase();
        var filter = String(root.querySelector("[data-calendar-provenance]").value || "");
        eventList.innerHTML = "";
        var shown = 0;
        var matched=allEvents().map(effective).sort(function(a,b){return String(a.start||"9999").localeCompare(String(b.start||"9999"));});
        var totalMatched=0;
        matched.forEach(function (event) {
            var searchable = [event.title,event.description,event.location,event.category].join(" ").toLowerCase();
            if (query && searchable.indexOf(query) < 0) return;
            if (filter === "hidden" && !event.hidden) return;
            if (filter && filter !== "hidden" && event.provenance !== filter) return;
            totalMatched += 1;if(!query&&totalMatched>eventLimit)return;
            shown += 1;
            var row = document.createElement("article");
            row.className = "h4bs-calendar-event-row" + (event.hidden ? " is-hidden" : "");
            row.innerHTML = "<div><h3>" + esc(event.title) + "</h3><span class='h4bs-calendar-pill'>" + esc(event.provenance === "local" ? "Added here" : "From Google Calendar") + "</span>" + (event.hidden ? "<span class='h4bs-calendar-pill'>Hidden from website</span>" : "") + "</div><div><strong>" + esc(humanDate(event.start)) + "</strong><br><span>Type: " + esc(event.category || "Not categorized") + "</span></div><div class='h4bs-calendar-actions'></div>";
            var actions = row.querySelector(".h4bs-calendar-actions");
            var edit = document.createElement("button"); edit.type="button"; edit.className="button"; edit.textContent="Edit"; edit.addEventListener("click",function(){openEditor(event.id,event.provenance);}); actions.appendChild(edit);
            var visibility = document.createElement("button"); visibility.type="button"; visibility.className="button"; visibility.textContent=event.hidden?"Include":"Hide"; visibility.addEventListener("click",function(){snapshot(); state.overrides=state.overrides||{}; state.overrides[event.id]=Object.assign({},state.overrides[event.id]||{},{hidden:!event.hidden}); markDirty("Visibility changed; save calendar"); render();}); actions.appendChild(visibility);
            if (event.provenance === "local") { var remove=document.createElement("button"); remove.type="button"; remove.className="button button-link-delete"; remove.textContent="Remove"; remove.addEventListener("click",function(){if(!window.confirm("Remove this local event? Synced events are never deleted upstream."))return;snapshot();state.local_events=(state.local_events||[]).filter(function(item){return item.id!==event.id;});markDirty("Local event removed; save calendar");render();}); actions.appendChild(remove); }
            eventList.appendChild(row);
        });
        root.querySelector("[data-calendar-empty]").hidden = shown !== 0;
        moreEvents.hidden=Boolean(query||totalMatched<=eventLimit);
        renderPreview();
    }
    function renderSources() {
        if (!sourceList) return;
        sourceList.innerHTML = "";
        (state.sources || []).forEach(function (source,index) {
            var card=document.createElement("article");card.className="h4bs-calendar-source-card";
            card.innerHTML="<div class='h4bs-calendar-source-fields'><label>Name<input data-key='name' value='"+esc(source.name)+"'></label><label>Provider<select data-key='provider'><option value='google'>Google Calendar</option><option value='feed'>JSON feed</option><option value='manual'>Manual only</option></select></label><label>Source ID<input data-key='id' value='"+esc(source.id)+"'></label><label>Calendar ID<input data-key='calendar_id' value='"+esc(source.calendar_id)+"'></label><label class='is-wide'>Feed URL<input type='url' data-key='feed_url' value='"+esc(source.feed_url)+"'></label></div><div><strong>Status: "+esc(source.status)+"</strong><br>Last sync: "+esc(source.last_sync_at||"Never")+"<br>Events: "+Number(source.last_sync_count||0)+(source.last_error?"<p class='h4bs-calendar-error'>"+esc(source.last_error)+"</p>":"")+"</div><div class='h4bs-calendar-actions'></div>";
            card.querySelector("[data-key=provider]").value=source.provider;
            card.querySelectorAll("[data-key]").forEach(function(input){input.addEventListener("change",function(){snapshot();source[input.dataset.key]=input.value;markDirty("Source changed; save before syncing");});});
            var actions=card.querySelector(".h4bs-calendar-actions");var sync=document.createElement("button");sync.type="button";sync.className="button button-primary";sync.textContent="Test & sync";sync.addEventListener("click",function(){syncSource(source.id,sync);});actions.appendChild(sync);
            var remove=document.createElement("button");remove.type="button";remove.className="button button-link-delete";remove.textContent="Remove source";remove.addEventListener("click",function(){if(!window.confirm("Remove this source from Help4? Upstream events are not deleted."))return;snapshot();state.sources.splice(index,1);markDirty("Source removed; save calendar");render();});actions.appendChild(remove);sourceList.appendChild(card);
        });
    }
    function field(label,key,type,wide) { return "<label"+(wide?" class='is-wide'":"")+"><span>"+label+"</span>"+(type==="textarea"?"<textarea name='"+key+"'></textarea>":"<input type='"+(type||"text")+"' name='"+key+"'>")+"</label>"; }
    function openEditor(id,provenance) {
        var original=allEvents().find(function(event){return event.id===id;})||{id:"local-"+Date.now(),provenance:"local",source_id:"",title:"",description:"",start:"",end:"",all_day:false,location:"",category:"",badge:"",url:"",event_status:"scheduled",timezone:"",venue_name:"",street_address:"",address_locality:"",address_region:"",postal_code:"",address_country:"US",ticket_url:"",offer_price:"",offer_currency:"USD",updated_at:"",extensions:{}};
        editing={original:clone(original),provenance:provenance||"local"};
        var current=effective(original);editorFields.innerHTML="<div class='h4bs-calendar-editor-grid'>"+field("Event title","title","text",true)+field("Starts","start","datetime-local")+field("Ends","end","datetime-local")+field("Short description","description","textarea",true)+"<div class='is-wide h4bs-calendar-image'><span>Event image</span><img alt='' hidden><input type='hidden' name='image_url'><button type='button' class='button' data-event-image>Choose from Media Library</button><button type='button' class='button' data-event-image-remove>Remove</button><small>Use an approved image with useful alternative text in Media Library.</small></div>"+field("Venue","venue_name")+field("Ticket or registration link","ticket_url","url",true)+"<label><span>Event status</span><select name='event_status'><option value='scheduled'>Scheduled</option><option value='cancelled'>Cancelled</option><option value='postponed'>Postponed</option><option value='rescheduled'>Rescheduled</option></select></label><label><span>Homepage</span><select name='featured'><option value=''>Do not feature</option><option value='1'>Feature on homepage</option></select></label><details class='is-wide'><summary>Advanced event details</summary><div class='h4bs-calendar-editor-grid'>"+field("Timezone","timezone")+field("Street address","street_address")+field("City / locality","address_locality")+field("State / region","address_region")+field("Postal code","postal_code")+field("Country code","address_country")+field("Category","category")+field("Badge","badge")+field("Price (0 for free)","offer_price","number")+field("Currency","offer_currency")+field("Source event link","url","url",true)+"</div></details></div>";
        ["title","start","end","description","image_url","timezone","event_status","featured","venue_name","street_address","address_locality","address_region","postal_code","address_country","category","badge","ticket_url","offer_price","offer_currency","url"].forEach(function(key){var input=editorFields.querySelector("[name="+key+"]");if(input)input.value=current[key]||"";});
        var imageInput=editorFields.querySelector("[name=image_url]"),imagePreview=editorFields.querySelector(".h4bs-calendar-image img");function showImage(url){imageInput.value=url||"";imagePreview.src=url||"";imagePreview.hidden=!url;}showImage(current.image_url);editorFields.querySelector("[data-event-image]").addEventListener("click",function(){if(!window.wp||!wp.media)return;var frame=wp.media({title:"Choose event image",library:{type:"image"},multiple:false});frame.on("select",function(){var item=frame.state().get("selection").first().toJSON();showImage(item.url);});frame.open();});editorFields.querySelector("[data-event-image-remove]").addEventListener("click",function(){showImage("");});
        if(original.provenance==="source") { ["start","end","url"].forEach(function(key){var input=editorFields.querySelector("[name="+key+"]");input.disabled=true;input.title="This value comes from the connected source.";}); var notice=document.createElement("p");notice.className="description is-wide";notice.textContent="Date, time, and source link stay owned by the connected calendar. Help4 can safely override presentation, status, venue details, and ticket information without changing the source.";editorFields.querySelector(".h4bs-calendar-editor-grid").prepend(notice); }
        root.querySelector("[data-calendar-editor-title]").textContent=(original.title?"Edit "+original.title:"Add local event")+(original.provenance==="source"?" (synced source)":"");
        if(editorStatus)editorStatus.textContent="";
        dialog.showModal();editorFields.querySelector("[name=title]").focus();
    }
    function applyEditor(event) {
        event.preventDefault();var values={};editorFields.querySelectorAll("[name]").forEach(function(input){values[input.name]=input.value;});
        if(!String(values.title||"").trim()){var title=editorFields.querySelector("[name=title]");title.setAttribute("aria-invalid","true");title.focus();return;}
        snapshot();
        if(editing.original.provenance==="source") { state.overrides=state.overrides||{};state.overrides[editing.original.id]=Object.assign({},state.overrides[editing.original.id]||{},values); }
        else { editing.pendingUpdatedAt=editing.pendingUpdatedAt||new Date().toISOString();var next=Object.assign({},editing.original,values,{provenance:"local",updated_at:editing.pendingUpdatedAt});var index=(state.local_events||[]).findIndex(function(item){return item.id===next.id;});if(index>=0)state.local_events[index]=next;else{state.local_events=state.local_events||[];state.local_events.push(next);} }
        markDirty("Saving event…");
        if(editorStatus)editorStatus.textContent="Saving event…";
        if(editorSubmit)editorSubmit.disabled=true;
        save({fromEditor:true}).then(function(saved){
            if(saved){dialog.close();render();}
        }).finally(function(){if(editorSubmit)editorSubmit.disabled=false;});
    }
    function humanDate(value){if(!value)return "Date not set";var date=new Date(value);if(Number.isNaN(date.getTime()))return "Check date and time";var options=value.length>10?{dateStyle:"medium",timeStyle:"short"}:{dateStyle:"medium"};return new Intl.DateTimeFormat(undefined,options).format(date);}
    function renderPreview(){var preview=root.querySelector("[data-calendar-preview]");if(!preview)return;var items=allEvents().map(effective).filter(function(event){return !event.hidden;}).slice(0,6);preview.innerHTML=items.length?items.map(function(event){return "<article><strong>"+esc(humanDate(event.start))+"</strong><h3>"+esc(event.title)+"</h3><p>"+esc(event.description)+"</p></article>";}).join(""):"<p>No visible events yet.</p>";}
    function renderRecovery(){var target=root.querySelector("[data-calendar-recovery]");target.innerHTML="";(config.recovery||[]).forEach(function(entry,index){var row=document.createElement("p");row.textContent="Saved before "+(entry.created_at||"a prior change")+" ";var button=document.createElement("button");button.type="button";button.className="button";button.textContent="Restore";button.addEventListener("click",function(){if(window.confirm("Restore this calendar workspace revision?"))recover(index);});row.appendChild(button);target.appendChild(row);});if(!(config.recovery||[]).length)target.textContent="No recovery points yet.";}
    function render(){renderEvents();renderSources();renderRecovery();syncHistoryButtons();}
    function undo(){if(!history.length)return;future.push(clone(state));state=normalizeWorkspace(history.pop());markDirty("Undo applied; save calendar");render();}
    function redo(){if(!future.length)return;history.push(clone(state));state=normalizeWorkspace(future.pop());markDirty("Redo applied; save calendar");render();}
    function request(action,extra){var body=new URLSearchParams(Object.assign({action:action,nonce:config.nonce},extra||{}));return fetch(config.ajaxUrl,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/x-www-form-urlencoded;charset=UTF-8"},body:body.toString()}).then(function(response){return response.json().then(function(json){if(!response.ok||!json.success)throw Object.assign(new Error(json.data&&json.data.message?json.data.message:"Calendar request failed"),{payload:json});return json.data;});});}
    function save(options){
        options=options||{};
        if(!dirty||saving)return Promise.resolve(false);
        var payload=JSON.stringify(state);
        if(!pendingRequestId||pendingRequestPayload!==payload){pendingRequestId=uuid();pendingRequestPayload=payload;}
        saving=true;setSaveState("saving","Saving calendar…");
        return request("h4bs_calendar_save",{revision:String(state.revision||1),workspace:payload,request_id:pendingRequestId}).then(function(data){state=normalizeWorkspace(data.workspace);config.recovery=Array.isArray(data.recovery)?data.recovery:config.recovery;dirty=false;history=[];future=[];pendingRequestId="";pendingRequestPayload="";render();setSaveState("clean",data.message||"All changes saved");if(options.fromEditor&&editorStatus)editorStatus.textContent="Event saved.";return true;}).catch(function(error){var message=error.message+" Your unsaved changes are still here.";setSaveState("error",message);if(options.fromEditor&&editorStatus)editorStatus.textContent=message;return false;}).finally(function(){saving=false;setSaveState(saveState.dataset.state||"clean",saveState.textContent);});
    }
    function syncSource(id,button){if(dirty){setSaveState("error","Save source changes before syncing");return;}button.disabled=true;button.textContent="Syncing…";request("h4bs_calendar_sync",{source_id:id}).then(function(data){state=normalizeWorkspace(data.workspace);setSaveState("clean",data.message);render();}).catch(function(error){if(error.payload&&error.payload.data&&error.payload.data.workspace)state=normalizeWorkspace(error.payload.data.workspace);setSaveState("error",error.message);render();}).finally(function(){button.disabled=false;button.textContent="Test & sync";});}
    function recover(index){if(saving)return;saving=true;setSaveState("saving","Restoring calendar…");request("h4bs_calendar_recover",{index:String(index)}).then(function(data){state=normalizeWorkspace(data.workspace);config.recovery=Array.isArray(data.recovery)?data.recovery:config.recovery;dirty=false;history=[];future=[];render();setSaveState("clean",data.message);}).catch(function(error){setSaveState("error",error.message);}).finally(function(){saving=false;setSaveState(saveState.dataset.state||"clean",saveState.textContent);});}
    root.querySelectorAll("[data-calendar-tab]").forEach(function(button){button.addEventListener("click",function(){root.querySelectorAll("[data-calendar-tab]").forEach(function(other){other.classList.toggle("nav-tab-active",other===button);});root.querySelectorAll("[data-calendar-panel]").forEach(function(panel){panel.hidden=panel.dataset.calendarPanel!==button.dataset.calendarTab;});});});
    root.querySelector("[data-calendar-search]").addEventListener("input",renderEvents);root.querySelector("[data-calendar-provenance]").addEventListener("change",renderEvents);
    moreEvents.addEventListener("click",function(){eventLimit+=15;renderEvents();});
    root.querySelector("[data-calendar-add]").addEventListener("click",function(){openEditor("","local");});
    var addSourceButton=root.querySelector("[data-calendar-add-source]");if(addSourceButton)addSourceButton.addEventListener("click",function(){snapshot();state.sources=state.sources||[];state.sources.push({id:"source-"+Date.now(),name:"New calendar",provider:"google",calendar_id:"",feed_url:"",enabled:true,status:"not_connected",last_sync_at:"",last_sync_count:0,last_error:"",etag:"",extensions:{}});markDirty("Source added; save calendar");render();});
    saveButton.addEventListener("click",save);
    root.querySelector("[data-calendar-undo]").addEventListener("click",undo);root.querySelector("[data-calendar-redo]").addEventListener("click",redo);
    root.querySelector("[data-calendar-editor-form]").addEventListener("submit",applyEditor);
    root.querySelector("[data-calendar-editor-close]").addEventListener("click",function(){dialog.close();});root.querySelector("[data-calendar-editor-cancel]").addEventListener("click",function(){dialog.close();});
    document.addEventListener("keydown",function(event){if((event.ctrlKey||event.metaKey)&&event.key.toLowerCase()==="s"){event.preventDefault();save();}if((event.ctrlKey||event.metaKey)&&event.key.toLowerCase()==="z"&&!dialog.open){event.preventDefault();if(event.shiftKey)redo();else undo();}});
    window.addEventListener("beforeunload",function(event){if(dirty){event.preventDefault();event.returnValue="";}});
    render();setSaveState("clean","All changes saved");
})();
