<?php
declare(strict_types=1);

require __DIR__ . '/partials/auth.php';
if (function_exists('require_teacher_login')) {
    require_teacher_login();
}
if (session_status() !== PHP_SESSION_ACTIVE) {
    session_start();
}

// Avatar Builder is a system-wide resource editor: Admin only.
$avatarBuilderRole = strtolower(trim((string)($_SESSION['user_role'] ?? '')));
if ($avatarBuilderRole !== 'admin') {
    http_response_code(403);
    header('Location: dashboard/');
    exit;
}

if (empty($_SESSION['avatar_builder_csrf'])) {
    $_SESSION['avatar_builder_csrf'] = bin2hex(random_bytes(32));
}
$csrf = (string)$_SESSION['avatar_builder_csrf'];

$manifestPath = __DIR__ . '/../assets/avatars/builder/manifest.json';
$manifest = null;
$error = '';

if (!is_file($manifestPath) || !is_readable($manifestPath)) {
    $error = 'Không đọc được assets/avatars/builder/manifest.json';
} else {
    $raw = file_get_contents($manifestPath);
    $manifest = json_decode((string)$raw, true);
    if (!is_array($manifest)) {
        $error = 'manifest.json không hợp lệ.';
        $manifest = null;
    }
}

$bases = is_array($manifest['categories']['base']['items'] ?? null)
    ? $manifest['categories']['base']['items'] : [];
$hairs = is_array($manifest['categories']['hair']['items'] ?? null)
    ? $manifest['categories']['hair']['items'] : [];

$defaultBase = (string)($manifest['defaults']['base'] ?? ($bases[0]['id'] ?? ''));
$defaultHair = (string)($manifest['defaults']['hair'] ?? ($hairs[0]['id'] ?? ''));
?>
<!doctype html>
<html lang="vi">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Avatar Builder | EnglishSpeak</title>
<style>
*{box-sizing:border-box}
:root{--blue:#0b4f9c;--muted:#315d82;--soft:#eef7ff;--border:#cfe4f5;--bg:#f7fbff;--white:#fff;--green:#137a48}
body{margin:0;background:var(--bg);font-family:"Segoe UI",Tahoma,Arial,sans-serif;color:#17324d}
.page{max-width:1120px;margin:0 auto;padding:20px}
.topbar{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:16px}
.topbar h1{margin:0;color:var(--blue);font-size:26px}
.topbar p{margin:4px 0 0;color:var(--muted);font-weight:650}
.back{display:inline-flex;align-items:center;gap:6px;color:var(--blue);text-decoration:none;font-weight:800}
.notice{padding:12px 14px;border-radius:12px;background:#fff2f0;color:#b42318;font-weight:800}
.workspace{display:grid;grid-template-columns:minmax(320px,420px) minmax(0,1fr);gap:18px}
.card{background:#fff;border:1px solid var(--border);border-radius:18px;box-shadow:0 6px 18px rgba(29,80,116,.06)}
.preview-card{padding:16px;position:sticky;top:16px;align-self:start}
.stage{position:relative;width:min(100%,360px);aspect-ratio:1/1;margin:0 auto;border:3px solid #fff;border-radius:50%;background:var(--soft);overflow:hidden;touch-action:none;cursor:grab;box-shadow:0 0 0 1px var(--border),0 6px 18px rgba(29,80,116,.10)}
.stage.dragging{cursor:grabbing}
.layer{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;pointer-events:none}
#baseLayer,#hairLayer{transform-origin:center center}
.preview-title{text-align:center;margin:0 0 12px;color:var(--blue);font-size:18px;font-weight:900}
.controls{margin-top:14px;padding:13px;border:1px dashed #b9d7ee;border-radius:14px;background:#f8fcff}
.controls h3{margin:0 0 8px;color:var(--blue);font-size:15px}
.control-row{display:grid;grid-template-columns:100px minmax(0,1fr) 58px;align-items:center;gap:10px;margin:9px 0}
.control-row label{font-size:13px;font-weight:800;color:var(--muted)}
.control-row input{width:100%}
.value{text-align:right;color:var(--blue);font-size:12px;font-weight:900}
.buttons{display:grid;grid-template-columns:1fr 1fr;gap:9px;margin-top:12px}
.btn{min-height:42px;border:1px solid var(--border);border-radius:12px;background:#fff;color:var(--blue);font-weight:900;cursor:pointer}
.btn.primary{background:var(--blue);border-color:var(--blue);color:#fff}
.status{min-height:20px;margin-top:9px;text-align:center;color:var(--green);font-size:13px;font-weight:800}
.library{padding:16px}
.section+.section{margin-top:18px}
.section-title{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}
.section-title h2{margin:0;color:var(--blue);font-size:18px}
.section-title span{color:var(--muted);font-size:12px;font-weight:800}
.grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:9px}
.choice{padding:7px;border:1px solid #d4e3ee;border-radius:13px;background:#fff;color:var(--muted);font:inherit;font-size:11px;font-weight:800;cursor:pointer}
.choice.selected{border:2px solid var(--blue);background:var(--soft);color:var(--blue)}
.thumb{display:block;width:100%;aspect-ratio:1/1;object-fit:contain;border-radius:9px;background:#f7fbff;margin-bottom:5px}
.help{margin:10px 0 0;color:#6b8193;font-size:12px;line-height:1.45}
@media(max-width:800px){.workspace{grid-template-columns:1fr}.preview-card{position:static}}
@media(max-width:500px){.page{padding:12px}.grid{grid-template-columns:repeat(3,minmax(0,1fr))}.control-row{grid-template-columns:82px minmax(0,1fr) 52px}}
</style>
</head>
<body>
<div class="page">
    <div class="topbar">
        <div>
            <a class="back" href="dashboard/">← Admin</a>
            <h1>Avatar Builder</h1>
            <p>Quản lý tài nguyên avatar hệ thống cho học sinh. Chỉ Admin có quyền chỉnh và lưu cấu hình.</p>
        </div>
    </div>

    <?php if ($error !== ''): ?>
        <div class="notice"><?= htmlspecialchars($error, ENT_QUOTES, 'UTF-8') ?></div>
    <?php else: ?>
    <div class="workspace">
        <section class="card preview-card">
            <h2 class="preview-title">Xem trước</h2>
            <div class="stage" id="stage">
                <img class="layer" id="baseLayer" alt="">
                <img class="layer" id="hairLayer" alt="">
            </div>

            <div class="controls">
                <h3>Chỉnh Base</h3>
                <div class="control-row"><label for="baseScale">Kích thước</label><input id="baseScale" type="range" min="60" max="140" step="1"><span class="value" id="baseScaleValue"></span></div>
                <div class="control-row"><label for="baseOffsetY">Lên / xuống</label><input id="baseOffsetY" type="range" min="-120" max="120" step="1"><span class="value" id="baseYValue"></span></div>
                <div class="buttons">
                    <button class="btn" type="button" id="baseResetBtn">Đặt lại Base</button>
                    <button class="btn primary" type="button" id="baseCenterBtn">Căn giữa</button>
                </div>

                <h3 style="margin-top:16px">Chỉnh tóc</h3>
                <div class="control-row"><label for="scale">Kích thước</label><input id="scale" type="range" min="45" max="125" step="1"><span class="value" id="scaleValue"></span></div>
                <div class="control-row"><label for="offsetY">Lên / xuống</label><input id="offsetY" type="range" min="-120" max="120" step="1"><span class="value" id="yValue"></span></div>
                <div class="control-row"><label for="offsetX">Trái / phải</label><input id="offsetX" type="range" min="-120" max="120" step="1"><span class="value" id="xValue"></span></div>
                <div class="buttons">
                    <button class="btn" type="button" id="resetBtn">Đặt lại</button>
                    <button class="btn primary" type="button" id="saveBtn">Lưu vị trí tóc</button>
                </div>
                <div class="status" id="status"></div>
                <p class="help">Có thể chỉnh Base bằng thanh Kích thước/Lên xuống. Giữ Shift và kéo trên khung để kéo Base lên xuống; kéo bình thường để chỉnh tóc.</p>
            </div>
        </section>

        <section class="card library">
            <div class="section">
                <div class="section-title"><h2>Base</h2><span><?= count($bases) ?> mẫu</span></div>
                <div class="grid" id="baseGrid"></div>
            </div>
            <div class="section">
                <div class="section-title"><h2>Hair</h2><span><?= count($hairs) ?> kiểu</span></div>
                <div class="grid" id="hairGrid"></div>
            </div>
        </section>
    </div>
    <?php endif; ?>
</div>

<?php if ($error === ''): ?>
<script>
const csrf=<?= json_encode($csrf, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES) ?>;
const root='../assets/avatars/builder/';
const bases=<?= json_encode($bases, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES) ?>;
const hairs=<?= json_encode($hairs, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES) ?>;
let selectedBase=<?= json_encode($defaultBase) ?>;
let selectedHair=<?= json_encode($defaultHair) ?>;
let currentFit={scale:.84,offset_x:0,offset_y:-14};
let savedFit={...currentFit};
let currentBaseFit={scale:1,offset_y:0};
let savedBaseFit={...currentBaseFit};
const baseFits={};

const stage=document.getElementById('stage');
const baseLayer=document.getElementById('baseLayer');
const hairLayer=document.getElementById('hairLayer');
const baseGrid=document.getElementById('baseGrid');
const hairGrid=document.getElementById('hairGrid');
const baseScale=document.getElementById('baseScale');
const baseOffsetY=document.getElementById('baseOffsetY');
const baseScaleValue=document.getElementById('baseScaleValue');
const baseYValue=document.getElementById('baseYValue');
const baseResetBtn=document.getElementById('baseResetBtn');
const baseCenterBtn=document.getElementById('baseCenterBtn');
const scale=document.getElementById('scale');
const offsetX=document.getElementById('offsetX');
const offsetY=document.getElementById('offsetY');
const scaleValue=document.getElementById('scaleValue');
const xValue=document.getElementById('xValue');
const yValue=document.getElementById('yValue');
const resetBtn=document.getElementById('resetBtn');
const saveBtn=document.getElementById('saveBtn');
const status=document.getElementById('status');

function byId(list,id){return list.find(item=>item.id===id)||null}
function applyBaseFit(){
    baseLayer.style.transform=`translateY(${currentBaseFit.offset_y}px) scale(${currentBaseFit.scale})`;
    baseScale.value=String(Math.round(currentBaseFit.scale*100));
    baseOffsetY.value=String(Math.round(currentBaseFit.offset_y));
    baseScaleValue.textContent=Math.round(currentBaseFit.scale*100)+'%';
    baseYValue.textContent=Math.round(currentBaseFit.offset_y)+' px';
}
function applyFit(){
    hairLayer.style.transform=`translate(${currentFit.offset_x}px,${currentFit.offset_y}px) scale(${currentFit.scale})`;
    scale.value=String(Math.round(currentFit.scale*100));
    offsetX.value=String(Math.round(currentFit.offset_x));
    offsetY.value=String(Math.round(currentFit.offset_y));
    scaleValue.textContent=Math.round(currentFit.scale*100)+'%';
    xValue.textContent=Math.round(currentFit.offset_x)+' px';
    yValue.textContent=Math.round(currentFit.offset_y)+' px';
}
function render(){
    const base=byId(bases,selectedBase);
    const hair=byId(hairs,selectedHair);
    baseLayer.src=base?root+'base/'+base.file:'';
    const rememberedBaseFit=baseFits[selectedBase] || {scale:1,offset_y:0};
    currentBaseFit={...rememberedBaseFit};
    savedBaseFit={...rememberedBaseFit};
    applyBaseFit();
    hairLayer.src=hair?root+'hair/'+hair.file:'';

    const fit=hair?.fit||{};
    currentFit={scale:Number(fit.scale??.84),offset_x:Number(fit.offset_x??0),offset_y:Number(fit.offset_y??-14)};
    savedFit={...currentFit};
    applyFit();
    status.textContent='';

    document.querySelectorAll('[data-base]').forEach(b=>b.classList.toggle('selected',b.dataset.base===selectedBase));
    document.querySelectorAll('[data-hair]').forEach(b=>b.classList.toggle('selected',b.dataset.hair===selectedHair));
}
function makeChoice(item,type){
    const b=document.createElement('button');
    b.type='button'; b.className='choice'; b.dataset[type]=item.id;
    const folder=type==='base'?'base':'hair';
    b.innerHTML=`<img class="thumb" src="${root}${folder}/${item.file}" alt=""><span>${item.label}</span>`;
    b.addEventListener('click',()=>{if(type==='base')selectedBase=item.id;else selectedHair=item.id;render()});
    return b;
}
bases.forEach(x=>baseGrid.appendChild(makeChoice(x,'base')));
hairs.forEach(x=>hairGrid.appendChild(makeChoice(x,'hair')));

baseScale.addEventListener('input',()=>{currentBaseFit.scale=Number(baseScale.value)/100;baseFits[selectedBase]={...currentBaseFit};applyBaseFit()});
baseOffsetY.addEventListener('input',()=>{currentBaseFit.offset_y=Number(baseOffsetY.value);baseFits[selectedBase]={...currentBaseFit};applyBaseFit()});
baseResetBtn.addEventListener('click',()=>{currentBaseFit={...savedBaseFit};baseFits[selectedBase]={...currentBaseFit};applyBaseFit();status.textContent='Đã đặt lại Base.'});
baseCenterBtn.addEventListener('click',()=>{currentBaseFit.offset_y=0;baseFits[selectedBase]={...currentBaseFit};applyBaseFit();status.textContent='Đã căn giữa Base.'});

scale.addEventListener('input',()=>{currentFit.scale=Number(scale.value)/100;applyFit()});
offsetX.addEventListener('input',()=>{currentFit.offset_x=Number(offsetX.value);applyFit()});
offsetY.addEventListener('input',()=>{currentFit.offset_y=Number(offsetY.value);applyFit()});
resetBtn.addEventListener('click',()=>{currentFit={...savedFit};applyFit();status.textContent='Đã đặt lại.'});

let drag=null;
stage.addEventListener('pointerdown',e=>{
    if(e.shiftKey){
        drag={type:'base',y:e.clientY,oy:currentBaseFit.offset_y};
    }else{
        if(!selectedHair)return;
        drag={type:'hair',x:e.clientX,y:e.clientY,ox:currentFit.offset_x,oy:currentFit.offset_y};
    }
    stage.setPointerCapture?.(e.pointerId);stage.classList.add('dragging');
});
stage.addEventListener('pointermove',e=>{
    if(!drag)return;
    if(drag.type==='base'){
        currentBaseFit.offset_y=drag.oy+(e.clientY-drag.y);baseFits[selectedBase]={...currentBaseFit};applyBaseFit();
    }else{
        currentFit.offset_x=drag.ox+(e.clientX-drag.x);
        currentFit.offset_y=drag.oy+(e.clientY-drag.y);applyFit();
    }
});
function stopDrag(){drag=null;stage.classList.remove('dragging')}
stage.addEventListener('pointerup',stopDrag);
stage.addEventListener('pointercancel',stopDrag);

saveBtn.addEventListener('click',async()=>{
    const hair=byId(hairs,selectedHair);
    if(!hair)return;
    saveBtn.disabled=true;status.textContent='Đang lưu...';
    try{
        const body=new URLSearchParams({csrf_token:csrf,hair_id:hair.id,scale:String(currentFit.scale),offset_x:String(Math.round(currentFit.offset_x)),offset_y:String(Math.round(currentFit.offset_y))});
        const response=await fetch('avatar-builder-save.php',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded;charset=UTF-8'},body});
        const result=await response.json();
        if(!response.ok||!result.ok)throw new Error(result.message||'save failed');
        hair.fit={...currentFit};savedFit={...currentFit};status.textContent='Đã lưu vị trí tóc.';
    }catch(err){status.textContent='Chưa lưu được vị trí tóc.'}
    finally{saveBtn.disabled=false}
});
render();
</script>
<?php endif; ?>
</body>
</html>
