(function () {
  const cfg = window.CITY_BOY_CONFIG || {};
  const OUTPUT_W = 1080, OUTPUT_H = 1350;
  const els = {
    mediaUpload: document.getElementById('mediaUpload'),
    cameraCapture: document.getElementById('cameraCapture'),
    uploadProgressBar: document.getElementById('uploadProgressBar'),
    uploadStatus: document.getElementById('uploadStatus'),
    templateGrid: document.getElementById('templateGrid'),
    zoomRange: document.getElementById('zoomRange'),
    xRange: document.getElementById('xRange'),
    yRange: document.getElementById('yRange'),
    resetBtn: document.getElementById('resetBtn'),
    fitBtn: document.getElementById('fitBtn'),
    downloadPngBtn: document.getElementById('downloadPngBtn'),
    exportProgressBar: document.getElementById('exportProgressBar'),
    exportStatus: document.getElementById('exportStatus'),
    previewCanvas: document.getElementById('previewCanvas'),
  };
  if (!els.previewCanvas) return;

  const previewCtx = els.previewCanvas.getContext('2d');
  const exportCanvas = document.createElement('canvas');
  exportCanvas.width = OUTPUT_W; exportCanvas.height = OUTPUT_H;
  const exportCtx = exportCanvas.getContext('2d');

  const state = {frames:[],selectedFrame:0,mediaImage:null,zoom:1,offsetX:0,offsetY:0,dragging:false,dragStartX:0,dragStartY:0,dragOffsetX:0,dragOffsetY:0};

  function setUploadProgress(percent, text, cls=''){els.uploadProgressBar.style.width=percent+'%';els.uploadStatus.textContent=text;els.uploadStatus.className='status '+cls}
  function setExportProgress(percent, text, cls=''){els.exportProgressBar.style.width=percent+'%';els.exportStatus.textContent=text;els.exportStatus.className='status '+cls}
  function fileToDataUrl(file){return new Promise((resolve,reject)=>{const r=new FileReader();r.onload=()=>resolve(r.result);r.onerror=reject;r.readAsDataURL(file);});}
  function loadImage(src){return new Promise((resolve,reject)=>{const img=new Image();img.onload=()=>resolve(img);img.onerror=reject;img.src=src;});}
  function getDrawMetrics(){if(!state.mediaImage)return null;const size={width:state.mediaImage.width,height:state.mediaImage.height};const canvasRatio=OUTPUT_W/OUTPUT_H,mediaRatio=size.width/size.height;let drawWidth,drawHeight;if(mediaRatio>canvasRatio){drawHeight=OUTPUT_H*state.zoom;drawWidth=size.width*(drawHeight/size.height);}else{drawWidth=OUTPUT_W*state.zoom;drawHeight=size.height*(drawWidth/size.width);}return{x:(OUTPUT_W-drawWidth)/2+state.offsetX,y:(OUTPUT_H-drawHeight)/2+state.offsetY,drawWidth,drawHeight};}
  function drawPlaceholder(ctx){const g=ctx.createLinearGradient(0,0,0,OUTPUT_H);g.addColorStop(0,'#dfe6f2');g.addColorStop(1,'#c8d3e3');ctx.fillStyle=g;ctx.fillRect(0,0,OUTPUT_W,OUTPUT_H);ctx.fillStyle='#42526b';ctx.textAlign='center';ctx.textBaseline='middle';ctx.font='bold 54px Arial';ctx.fillText('Upload photo',OUTPUT_W/2,OUTPUT_H/2-20);ctx.font='28px Arial';ctx.fillText('Use upload or phone camera',OUTPUT_W/2,OUTPUT_H/2+36);}
  function drawAll(ctx){ctx.clearRect(0,0,OUTPUT_W,OUTPUT_H);const m=getDrawMetrics();if(!m){drawPlaceholder(ctx);}else{ctx.fillStyle='#e8edf6';ctx.fillRect(0,0,OUTPUT_W,OUTPUT_H);ctx.drawImage(state.mediaImage,m.x,m.y,m.drawWidth,m.drawHeight);}const frame=state.frames[state.selectedFrame];if(frame&&frame.img)ctx.drawImage(frame.img,0,0,OUTPUT_W,OUTPUT_H);}
  function drawPreview(){drawAll(previewCtx);}
  async function handleMediaFile(file){if(!file)return;setUploadProgress(10,'Reading selected photo...');const dataUrl=await fileToDataUrl(file);setUploadProgress(55,'Loading photo...');state.mediaImage=await loadImage(dataUrl);state.zoom=1;state.offsetX=0;state.offsetY=0;syncInputs();drawPreview();setUploadProgress(100,'Photo loaded successfully.','good');}
  function syncInputs(){els.zoomRange.value=state.zoom;els.xRange.value=state.offsetX;els.yRange.value=state.offsetY;}
  function updateFromInputs(){state.zoom=parseFloat(els.zoomRange.value);state.offsetX=parseFloat(els.xRange.value);state.offsetY=parseFloat(els.yRange.value);drawPreview();}
  function renderTemplates(){els.templateGrid.innerHTML='';state.frames.forEach((frame,index)=>{const card=document.createElement('div');card.className='template-card'+(index===state.selectedFrame?' active':'');const preview=document.createElement('div');preview.className='template-preview';const img=document.createElement('img');img.src=frame.src;preview.appendChild(img);const title=document.createElement('div');title.className='template-title';title.textContent=frame.name||('Frame '+(index+1));card.append(preview,title);card.onclick=()=>{state.selectedFrame=index;renderTemplates();drawPreview();};els.templateGrid.appendChild(card);});}
  function exportPng(){if(!state.mediaImage){setExportProgress(0,'Upload a photo first to download PNG.','bad');return;}drawAll(exportCtx);exportCanvas.toBlob((blob)=>{const url=URL.createObjectURL(blob);const a=document.createElement('a');a.href=url;a.download='city-boy-movement-frame.png';a.click();setTimeout(()=>URL.revokeObjectURL(url),3000);setExportProgress(100,'PNG downloaded successfully.','good');},'image/png');}
  function bindDrag(){function start(x,y){state.dragging=true;els.previewCanvas.classList.add('dragging');state.dragStartX=x;state.dragStartY=y;state.dragOffsetX=state.offsetX;state.dragOffsetY=state.offsetY;}function move(x,y){if(!state.dragging)return;const rect=els.previewCanvas.getBoundingClientRect();const sx=OUTPUT_W/rect.width,sy=OUTPUT_H/rect.height;state.offsetX=state.dragOffsetX+(x-state.dragStartX)*sx;state.offsetY=state.dragOffsetY+(y-state.dragStartY)*sy;syncInputs();drawPreview();}function end(){state.dragging=false;els.previewCanvas.classList.remove('dragging');}els.previewCanvas.addEventListener('mousedown',e=>start(e.clientX,e.clientY));window.addEventListener('mousemove',e=>move(e.clientX,e.clientY));window.addEventListener('mouseup',end);els.previewCanvas.addEventListener('touchstart',e=>{const t=e.touches[0];start(t.clientX,t.clientY);},{passive:true});window.addEventListener('touchmove',e=>{if(!state.dragging)return;const t=e.touches[0];move(t.clientX,t.clientY);},{passive:true});window.addEventListener('touchend',end);}
  async function initFrames(){state.frames=[];const frames=Array.isArray(cfg.frames)?cfg.frames:[];for(const frame of frames){const src='frames/'+frame.file;try{const img=await loadImage(src);state.frames.push({src,img,name:frame.name||'Frame'});}catch(e){}}if(!state.frames.length){els.templateGrid.innerHTML='<div class="status bad">Frame images could not be loaded. Check your frames folder and filenames.</div>';}else{renderTemplates();drawPreview();}}
  function bindEvents(){els.mediaUpload.addEventListener('change',e=>handleMediaFile(e.target.files[0]));els.cameraCapture.addEventListener('change',e=>handleMediaFile(e.target.files[0]));els.zoomRange.addEventListener('input',updateFromInputs);els.xRange.addEventListener('input',updateFromInputs);els.yRange.addEventListener('input',updateFromInputs);els.resetBtn.addEventListener('click',()=>{state.zoom=1;state.offsetX=0;state.offsetY=0;syncInputs();drawPreview();});els.fitBtn.addEventListener('click',()=>{state.zoom=1;state.offsetX=0;state.offsetY=0;syncInputs();drawPreview();});els.downloadPngBtn.addEventListener('click',exportPng);}
  bindEvents();bindDrag();initFrames();drawPreview();
})();