@model CharacterAvatarCropViewModel
@{
    ViewData["Title"] = "Create Avatar";
}

<nav class="breadcrumb-trail" aria-label="Breadcrumb">
    <a asp-action="Details" asp-route-id="@Model.CharacterID">@Model.CharacterName</a>
    <span>Create Avatar</span>
</nav>

<div class="page-heading compact">
    <div>
        <p class="eyebrow">Character Avatar</p>
        <h1>Create Avatar</h1>
        <p class="lead-text">Choose a square crop. The original gallery image will be preserved.</p>
    </div>
</div>

@if (TempData["ImageError"] is string imageError)
{
    <div class="alert alert-warning">@imageError</div>
}

<form asp-action="SaveAvatar" method="post" class="edit-panel character-avatar-crop-form" data-avatar-crop-form>
    <input asp-for="CharacterID" type="hidden" />
    <input asp-for="CharacterImageID" type="hidden" />
    <input asp-for="CropX" type="hidden" data-crop-x />
    <input asp-for="CropY" type="hidden" data-crop-y />
    <input asp-for="CropSize" type="hidden" data-crop-size />

    <div class="character-avatar-crop-layout">
        <div class="character-avatar-crop-stage" data-crop-stage>
            <img src="@Model.ImagePath" alt="" data-crop-image />
            <div class="character-avatar-crop-box" data-crop-box>
                <span></span>
            </div>
        </div>
        <div class="character-avatar-crop-side">
            <p class="eyebrow">Preview</p>
            <div class="character-avatar-preview" data-avatar-preview>
                <img src="@Model.ImagePath" alt="" data-preview-image />
            </div>
            @if (!string.IsNullOrWhiteSpace(Model.Caption))
            {
                <p class="muted">@Model.Caption</p>
            }
            <label class="form-label" for="cropZoom">Crop size</label>
            <input class="form-range" id="cropZoom" type="range" min="20" max="100" value="70" data-crop-size-slider />
        </div>
    </div>

    <div class="button-row mt-3">
        <button class="btn btn-primary" type="submit">Save avatar</button>
        <a class="btn btn-outline-secondary" asp-action="Details" asp-route-id="@Model.CharacterID">Cancel</a>
    </div>
</form>

@section Scripts {
    <script>
        (() => {
            const form = document.querySelector("[data-avatar-crop-form]");
            if (!form) return;

            const stage = form.querySelector("[data-crop-stage]");
            const image = form.querySelector("[data-crop-image]");
            const box = form.querySelector("[data-crop-box]");
            const slider = form.querySelector("[data-crop-size-slider]");
            const preview = form.querySelector("[data-avatar-preview]");
            const previewImage = form.querySelector("[data-preview-image]");
            const cropX = form.querySelector("[data-crop-x]");
            const cropY = form.querySelector("[data-crop-y]");
            const cropSize = form.querySelector("[data-crop-size]");
            let crop = { x: 0, y: 0, size: 0 };
            let dragging = false;
            let dragOffset = { x: 0, y: 0 };

            const clamp = (value, min, max) => Math.min(Math.max(value, min), max);

            const imageRect = () => {
                const stageRect = stage.getBoundingClientRect();
                const imgRect = image.getBoundingClientRect();
                return {
                    x: imgRect.left - stageRect.left,
                    y: imgRect.top - stageRect.top,
                    width: imgRect.width,
                    height: imgRect.height
                };
            };

            const sync = () => {
                const rect = imageRect();
                const minSide = Math.min(rect.width, rect.height);
                const percent = Number(slider.value) / 100;
                crop.size = Math.max(24, minSide * percent);
                crop.x = clamp(crop.x, rect.x, rect.x + rect.width - crop.size);
                crop.y = clamp(crop.y, rect.y, rect.y + rect.height - crop.size);

                box.style.width = `${crop.size}px`;
                box.style.height = `${crop.size}px`;
                box.style.left = `${crop.x}px`;
                box.style.top = `${crop.y}px`;

                const naturalScaleX = image.naturalWidth / rect.width;
                const naturalScaleY = image.naturalHeight / rect.height;
                cropX.value = Math.round((crop.x - rect.x) * naturalScaleX);
                cropY.value = Math.round((crop.y - rect.y) * naturalScaleY);
                cropSize.value = Math.round(crop.size * Math.min(naturalScaleX, naturalScaleY));

                const previewSize = preview.clientWidth || 180;
                const scale = previewSize / crop.size;
                previewImage.style.width = `${rect.width * scale}px`;
                previewImage.style.height = `${rect.height * scale}px`;
                previewImage.style.transform = `translate(${-(crop.x - rect.x) * scale}px, ${-(crop.y - rect.y) * scale}px)`;
            };

            const resetCrop = () => {
                const rect = imageRect();
                const minSide = Math.min(rect.width, rect.height);
                crop.size = minSide * (Number(slider.value) / 100);
                crop.x = rect.x + (rect.width - crop.size) / 2;
                crop.y = rect.y + (rect.height - crop.size) / 2;
                sync();
            };

            image.addEventListener("load", resetCrop);
            if (image.complete) window.requestAnimationFrame(resetCrop);
            window.addEventListener("resize", resetCrop);
            slider.addEventListener("input", sync);

            box.addEventListener("pointerdown", (event) => {
                dragging = true;
                box.setPointerCapture(event.pointerId);
                dragOffset = { x: event.offsetX, y: event.offsetY };
            });

            box.addEventListener("pointermove", (event) => {
                if (!dragging) return;
                const stageRect = stage.getBoundingClientRect();
                const rect = imageRect();
                crop.x = clamp(event.clientX - stageRect.left - dragOffset.x, rect.x, rect.x + rect.width - crop.size);
                crop.y = clamp(event.clientY - stageRect.top - dragOffset.y, rect.y, rect.y + rect.height - crop.size);
                sync();
            });

            box.addEventListener("pointerup", () => {
                dragging = false;
            });

            form.addEventListener("submit", sync);
        })();
    </script>
}
