(function () {

    function qaEscapeHtml(value) {
        return String(value ?? "")
            .replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;")
            .replace(/"/g, "&quot;")
            .replace(/'/g, "&#39;");
    }

    function qaSafeUrl(url) {
        const v = String(url ?? "").trim();
        return /^(https?:|data:image\/)/i.test(v) ? qaEscapeHtml(v) : "";
    }

    function qaEscapeJsArg(value) {
        return qaEscapeHtml(JSON.stringify(String(value ?? "")));
    }
    const NEW_RELEASE_VALUE = "__new_release__";

    let allReleases = [];
    let availableReleases = [];
    let relatedReleases = [];

    let dropdownEl;
    let listEl;
    let emptyEl;
    let releasesLoadingEl;
    let releasesContentEl;

    async function init() {
        cacheDom();
        wireEvents();
        showReleasesLoading();
        try {
            await loadAllReleases();
            renderDropdown();
        } catch (err) {
            console.error(err);
            showDropdownError("Failed to load releases");
        }
        finally {
            hideReleasesLoading();
        }
    }

    function dispose() {
        // optional cleanup later
    }

    function cacheDom() {
        dropdownEl = document.getElementById("qa-release-dropdown");
        listEl = document.getElementById("qa-release-list");
        emptyEl = document.getElementById("qa-release-empty");
        releasesLoadingEl = document.getElementById("qa-releases-loading");
        releasesContentEl = document.getElementById("qa-releases-content");

    }

    function wireEvents() {
        document
            .getElementById("qa-release-add-btn")
            .addEventListener("click", onAddRelease);

        dropdownEl.addEventListener("change", onDropdownChange);
    }

    async function onDropdownChange() {
        if (dropdownEl.value !== NEW_RELEASE_VALUE) return;

        dropdownEl.value = "";

        const ctx = await getContext();
        window.open(buildCreateReleaseUrl(ctx), "_blank");
    }

    async function getContext() {
        if (!window.ensureSDKReady) {
            throw new Error("SDK not initialized");
        }
        await window.ensureSDKReady();
        return window.QAContext;
    }

    function showReleasesLoading() {
        releasesLoadingEl?.classList.remove("hidden");
        releasesContentEl?.classList.add("hidden");
    }

    function hideReleasesLoading() {
        releasesLoadingEl?.classList.add("hidden");
        releasesContentEl?.classList.remove("hidden");
    }

    function categorizeReleases(releases, currentWorkItemId) {

        const wiId = parseInt(currentWorkItemId, 10);
        const related = [];
        const available = [];

        releases.forEach(r => {
            const workItems = (r.workItems || "")
                .split(",")
                .map(id => parseInt(id.trim(), 10))
                .filter(Number.isFinite);

            if (Number.isFinite(wiId) && workItems.includes(wiId)) {
                related.push(r);
            } else {
                available.push(r);
            }
        });

        return { related, available };
    }


    function showDropdownError(message) {
        const dropdown = document.getElementById("releases-dropdown");
        if (!dropdown) {
            console.error(message);
            return;
        }

        dropdown.innerHTML = "";

        const option = document.createElement("option");
        option.disabled = true;
        option.selected = true;
        option.textContent = message;

        dropdown.appendChild(option);
    }

    async function loadAllReleases() {
        const ctx = await getContext();

        const res = await IndexLibrary.GetRequest({
            baseAPIUrl: ctx.baseAPIUrl,
            endpoint: `/api/Release/GetReleases/${ctx.projectName}`,
            azureAuthenticationHeader: ctx.accessToken,
            organizationName: ctx.organizationName,
            organizationId: ctx.organizationId,
            headers: {
                DevOpsProjectId: String(ctx.projectId)
            }
        });

        if (!res.ok) {
            throw new Error("Failed to load releases");
        }

        const apiData = await res.json();

        allReleases = normalizeReleases(apiData);
        const { related, available } = categorizeReleases(allReleases, ctx.workItemId);
        relatedReleases = related;
        availableReleases = available;
        renderRelatedReleases();

    }

    function normalizeReleases(apiReleases) {
        return apiReleases.map(r => ({
            releaseId: r.releaseId,
            releaseName: r.releaseName,
            workItems: r.workItems || ""
        }));
    }

    async function appendWorkItemToRelease(releaseId) {
        const ctx = await getContext();

        const payload = {
            releaseId: releaseId,
            organizationId: ctx.organizationId,
            devOpsProjectId: ctx.projectId,
            newWorkItemIds: [ctx.workItemId],
            modifiedBy: ctx.userEmail || ""
        };

        let res = await IndexLibrary.PostRequest({
            baseAPIUrl: ctx.baseAPIUrl,
            endpoint: `/api/Release/AppendWorkItems`,
            azureAuthenticationHeader: ctx.accessToken,
            organizationName: ctx.organizationName,
            organizationId: ctx.organizationId,
            headers: {
                DevOpsProjectId: String(ctx.projectId)
            },
            body: payload
        });

        // Backward-compatible fallback in case backend only accepts PATCH.
        if (!res.ok && (res.status === 404 || res.status === 405)) {
            res = await IndexLibrary.PatchRequest({
                baseAPIUrl: ctx.baseAPIUrl,
                endpoint: "/api/Release/AppendWorkItems",
                azureAuthenticationHeader: ctx.accessToken,
                organizationName: ctx.organizationName,
                organizationId: ctx.organizationId,
                headers: {
                    DevOpsProjectId: String(ctx.projectId)
                },
                body: payload
            });
        }

        if (!res.ok) {
            const text = await res.text();
            throw new Error(text || "Failed to add work item to release");
        }
    }

    async function removeWorkItemFromReleaseApi(releaseId) {
        const ctx = await getContext();

        const workItemId = parseInt(ctx.workItemId, 10);

        const res = await IndexLibrary.DeleteRequest({
            baseAPIUrl: ctx.baseAPIUrl,
            endpoint: `/api/Release/${releaseId}/workitems/${workItemId}`,
            azureAuthenticationHeader: ctx.accessToken,
            organizationName: ctx.organizationName,
            organizationId: ctx.organizationId,
            headers: {
                DevOpsProjectId: String(ctx.projectId)
            }
        });

        if (!res.ok) {
            const text = await res.text();
            throw new Error(text || "Failed to remove work item from release");
        }
    }

    /* -------------------------------------------------------------
       Rendering
    ------------------------------------------------------------- */

    function buildReleaseUrl(ctx, releaseId) {
        const hubId = "release-groups-hub-group.create-release";

        return (
            `https://dev.azure.com/${ctx.organizationName}/` +
            `${ctx.projectName}/_apps/hub/` +
            `${ctx.publisherId}.${ctx.extensionId}.${hubId}` +
            `?rId=${releaseId}`
        );
    }

    function buildCreateReleaseUrl(ctx) {
        const hubId = "release-groups-hub-group.create-release";

        return (
            `https://dev.azure.com/${ctx.organizationName}/` +
            `${ctx.projectName}/_apps/hub/` +
            `${ctx.publisherId}.${ctx.extensionId}.${hubId}`
        );
    }

    function renderDropdown() {
        dropdownEl.innerHTML = `<option value="">Select a release…</option>`;

        if (!availableReleases.length) {
            dropdownEl.innerHTML +=
                `<option disabled>No available releases</option>`;
        } else {
            availableReleases.forEach(r => {
                const opt = document.createElement("option");
                opt.value = r.releaseId;
                opt.textContent = r.releaseName;
                dropdownEl.appendChild(opt);
            });
        }

        const newReleaseOpt = document.createElement("option");
        newReleaseOpt.value = NEW_RELEASE_VALUE;
        newReleaseOpt.textContent = "+ New release";
        dropdownEl.appendChild(newReleaseOpt);
    }

    async function renderRelatedReleases() {
        listEl.innerHTML = "";

        if (!relatedReleases.length) {
            emptyEl.classList.remove("hidden");
            return;
        }

        emptyEl.classList.add("hidden");
        const ctx = await getContext();

        relatedReleases.forEach(r => {
            const item = document.createElement("div");
            item.className = "qa-suggestion-item qa-release-item";

            const releaseUrl = buildReleaseUrl(ctx, r.releaseId);

            item.innerHTML = `
                <div class="qa-release-item-main">
                    <a class="qa-suggestion-content" href="${qaSafeUrl(releaseUrl)}" target="_blank">
                        ${qaEscapeHtml(r.releaseName)}
                    </a>

                    <button
                        class="qa-icon-btn qa-release-open"
                        title="Open release"
                        data-id="${qaEscapeHtml(r.releaseId)}">
                        <i class="bi bi-box-arrow-up-right"></i>
                    </button>
                </div>

                <button
                    class="qa-del-icon-btn qa-release-remove"
                    title="Remove from release"
                    data-id="${qaEscapeHtml(r.releaseId)}">
                    <i class="bi bi-trash"></i>
                </button>
            `;

            item
                .querySelector(".qa-release-open")
                .addEventListener("click", () => window.open(releaseUrl, "_blank"));

            item
                .querySelector(".qa-release-remove")
                .addEventListener("click", () => removeRelease(r.releaseId));

            listEl.appendChild(item);
        });
    }

    /* -------------------------------------------------------------
       Actions
    ------------------------------------------------------------- */
    async function onAddRelease() {
        const releaseId = Number(dropdownEl.value);
        if (!releaseId) return;

        const release = availableReleases.find(r => r.releaseId === releaseId);
        if (!release) return;

        try {
            const btn = document.getElementById("qa-release-add-btn");
            btn.disabled = true;

            await appendWorkItemToRelease(releaseId);

            availableReleases = availableReleases.filter(
                r => r.releaseId !== releaseId
            );

            relatedReleases.push(release);

            renderDropdown();
            renderRelatedReleases();

            dropdownEl.value = "";
            showSuccess("Work item added to release");

        } catch (err) {
            showError(err.message || "Failed to add work item to release");
        } finally {
            document.getElementById("qa-release-add-btn").disabled = false;
        }
    }


    async function removeRelease(releaseId) {
        const confirmed = await confirmAction({
            text: "This work item will be removed from the selected release.",
            confirmText: "Remove"
        });

        if (!confirmed) return;

        const btn = document.querySelector(
            `.qa-release-remove[data-id="${releaseId}"]`
        );

        if (btn) {
            btn.disabled = true;
            btn.classList.add("disabled");
        }

        try {
            await removeWorkItemFromReleaseApi(releaseId);

            const release = relatedReleases.find(r => r.releaseId === releaseId);

            relatedReleases = relatedReleases.filter(
                r => r.releaseId !== releaseId
            );

            if (release) {
                availableReleases.push(release);
            }

            renderRelatedReleases();
            renderDropdown();
            showSuccess("Work item removed from release");


        } catch (err) {
            showError(err.message || "Failed to remove work item from release");

            if (btn) {
                btn.disabled = false;
                btn.classList.remove("disabled");
            }
        }
    }


    /* -------------------------------------------------------------
       Register screen
    ------------------------------------------------------------- */
    ScreenManager.register("releases", {
        init,
        dispose
    });

})();
