/**
 * Client Penpot API Direct — accès port 9003 (backend sans nginx)
 * update-file avec changes add-obj pour contrôle pixel-perfect
 * 
 * Clés API response : kebab-case ("default-team-id")
 * Clés envoi body   : kebab-case (via toKebab())
 * Clés obj shapes   : camelCase → converties par toKebab()
 */
import http from 'http';
import { randomUUID } from 'crypto';

const TOKEN = process.env.PENPOT_TOKEN;
const HOST  = '192.168.1.150';
const PORT  = 9003;

// ─── RPC ─────────────────────────────────────────────────────────────────────
function toKebab(obj) {
  if (Array.isArray(obj)) return obj.map(toKebab);
  if (obj && typeof obj === 'object') {
    return Object.fromEntries(Object.entries(obj).map(([k, v]) => [
      k.replace(/([a-z0-9])([A-Z])/g,'$1-$2').toLowerCase(), toKebab(v)
    ]));
  }
  return obj;
}

function rpc(cmd, body = {}) {
  return new Promise((resolve, reject) => {
    const payload = JSON.stringify(toKebab(body));
    const req = http.request({
      hostname: HOST, port: PORT,
      path: '/api/rpc/command/' + cmd, method: 'POST',
      headers: {
        'Authorization': 'Token ' + TOKEN,
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Content-Length': Buffer.byteLength(payload),
      }
    }, res => {
      let d = ''; res.on('data', c => d += c);
      res.on('end', () => { try { resolve(JSON.parse(d)); } catch { resolve(d); } });
    });
    req.on('error', reject);
    req.write(payload); req.end();
  });
}

// ─── Geometry ────────────────────────────────────────────────────────────────
function geo(x, y, w, h) {
  return {
    selrect: { x, y, width: w, height: h, x1: x, y1: y, x2: x+w, y2: y+h },
    points: [{x,y},{x:x+w,y},{x:x+w,y:y+h},{x,y:y+h}],
    transform: {a:1,b:0,c:0,d:1,e:0,f:0},
    transformInverse: {a:1,b:0,c:0,d:1,e:0,f:0},
  };
}

const ROOT = '00000000-0000-0000-0000-000000000000';

// ─── Builders ────────────────────────────────────────────────────────────────
function rect({ name, x, y, w, h, color, opacity=1, r=0, parentId, frameId: fid }) {
  const id = randomUUID();
  const pid = parentId || fid || ROOT;
  const fi  = fid || pid;
  return { type:'add-obj', id, pageId: PAGE_ID, frameId: fi, parentId: pid,
    obj: { id, type:'rect', name, x, y, width:w, height:h, parentId:pid, frameId:fi,
      fills:[{fillColor:color, fillOpacity:opacity}],
      ...(r > 0 && {r1:r,r2:r,r3:r,r4:r}),
      ...geo(x,y,w,h) }};
}

function text({ name, text: textContent, x, y, w, h, size, weight='400', color='#FFFFFF', align='center', spacing=0, parentId, frameId: fid }) {
  const t = textContent;
  const id = randomUUID();
  const pid = parentId || fid || ROOT;
  const fi  = fid || pid;
  return { type:'add-obj', id, pageId: PAGE_ID, frameId: fi, parentId: pid,
    obj: { id, type:'text', name, x, y, width:w, height:h, parentId:pid, frameId:fi,
      fills:[{fillColor:color, fillOpacity:1}],
      fontFamily:'Work Sans', fontSize:String(size), fontWeight:String(weight),
      fontStyle:'normal', verticalAlign:'top',
      content: { type:'root', children:[{ type:'paragraph-set', children:[{
        type:'paragraph', textAlign:align, children:[{
          text: t,
          fontId:'gfont-work-sans', fontFamily:'Work Sans',
          fontSize: String(size), fontWeight: String(weight),
          fontStyle:'normal', letterSpacing: String(spacing),
          lineHeight: 1.2, textDecoration:'none',
          fills:[{fillColor:color, fillOpacity:1}],
        }]
      }]}]},
      ...geo(x,y,w,h) }};
}

// ─── MAIN ────────────────────────────────────────────────────────────────────
// 1. Récupérer profil + projet
const prof = await rpc('get-profile');
// Le backend retourne les clés en kebab-case
const teamId    = prof['default-team-id']   || prof.defaultTeamId;
const projectId = prof['default-project-id'] || prof.defaultProjectId;
console.log(`👤 ${prof.fullname}  teamId=${teamId?.slice(0,8)}  projectId=${projectId?.slice(0,8)}`);
if (!teamId || !projectId) { console.error('❌ Profil incomplet:', JSON.stringify(prof)); process.exit(1); }

// 2. Supprimer ancien fichier si présent
const filesResult = await rpc('get-project-files', { projectId });
const filesArr = Array.isArray(filesResult) ? filesResult : (filesResult?.files || []);
for (const f of filesArr.filter(f => f.name?.includes('SOLDES Direct'))) {
  await rpc('delete-file', { id: f.id });
  console.log('🗑  Supprimé:', f.name);
}

// 3. Créer nouveau fichier
const file = await rpc('create-file', { projectId, name:'Affiche SOLDES Direct', isShared:false });
const FILE_ID = file.id;
const PAGE_ID = Object.keys(file.data?.pagesIndex || {})[0] || file.data?.pages?.[0];
console.log(`📄 File ${FILE_ID?.slice(0,8)}  Page ${PAGE_ID?.slice(0,8)}`);
if (!FILE_ID || !PAGE_ID) { console.error('❌ IDs manquants', file); process.exit(1); }

let revn = file.revn ?? 0;
const W = 600, H = 900;

// ─── 4. Shapes ───────────────────────────────────────────────────────────────
// Fond principal : rect rouge (pas frame — frame nécessite shapes[] explicite)
const FRAME_ID = ROOT; // On place tout au root, le rect rouge sert de fond visuel
const F = { parentId:ROOT, frameId:ROOT };

const changes = [
  // Fond rouge (rectangle plein cadre)
  rect({...F, name:'Fond rouge', x:0, y:0, w:W, h:H, color:'#C0392B'}),

  // ── Rectangles ──────────────────────────────────────────────────────────
  rect({...F, name:'Bande haut', x:0, y:0,   w:W, h:14, color:'#F1C40F'}),
  rect({...F, name:'Bande bas',  x:0, y:886,  w:W, h:14, color:'#F1C40F'}),
  rect({...F, name:'Header bg',  x:0, y:14,   w:W, h:92, color:'#7B241C'}),
  rect({...F, name:'Sep1',       x:80, y:445, w:440, h:3, color:'#F1C40F'}),
  rect({...F, name:'Badge',      x:90, y:460, w:420, h:70, color:'#F1C40F', r:35}),
  rect({...F, name:'Sep2',       x:80, y:775, w:440, h:3, color:'#F8C471'}),

  // ── Textes (width=W → textAlign:center centré sur 600px) ─────────────────
  text({...F, name:'Collection', text:'✦  Collection Printemps 2026  ✦',
    x:0, y:32, w:W, h:48, size:14, weight:'700', color:'#F1C40F', align:'center', spacing:4}),

  text({...F, name:'SOLDES', text:'SOLDES',
    x:0, y:118, w:W, h:100, size:88, weight:'900', color:'#F1C40F', align:'center', spacing:8}),

  text({...F, name:'-50%', text:'-50%',
    x:0, y:218, w:W, h:220, size:185, weight:'900', color:'#FFFFFF', align:'center'}),

  text({...F, name:'Sous-titre', text:'SUR TOUTES NOS CHAUSSURES',
    x:0, y:400, w:W, h:42, size:21, weight:'700', color:'#F1C40F', align:'center', spacing:3}),

  text({...F, name:'Offre', text:'⚡  OFFRE LIMITÉE  ⚡',
    x:90, y:476, w:420, h:40, size:22, weight:'900', color:'#7B241C', align:'center'}),

  text({...F, name:'Dates', text:'du 1er au 31 mars 2026',
    x:0, y:552, w:W, h:36, size:16, weight:'400', color:'#FADBD8', align:'center', spacing:2}),

  text({...F, name:'Chaussures', text:'👟   👠   👞',
    x:0, y:598, w:W, h:155, size:90, align:'center'}),

  text({...F, name:'Site web', text:'www.votre-boutique.fr',
    x:0, y:788, w:W, h:30, size:14, weight:'400', color:'#F8C471', align:'center', spacing:3}),

  text({...F, name:'Etoiles', text:'★  ★  ★  ★  ★',
    x:0, y:838, w:W, h:36, size:20, weight:'400', color:'#F1C40F', align:'center'}),
];

// 5. Envoyer shape par shape (revn incrémental)
let currentRevn = revn;
let ok = 0;
for (const change of changes) {
  const sid = randomUUID();
  const result = await rpc('update-file', {
    id: FILE_ID, sessionId: sid, revn: currentRevn, vern: 0, changes: [change]
  });
  if (result?.type === 'error' || result?.code) {
    console.error(`❌ "${change.obj?.name}":`, (result.explain || result.message || '').slice(0,120));
  } else {
    currentRevn = result?.revn ?? (currentRevn + 1);
    ok++;
    process.stdout.write(`  ✓ ${change.obj?.name || change.type}\n`);
  }
}
console.log(`\n✅ ${ok}/${changes.length} shapes créés`);
console.log(`🔗 http://192.168.1.150:9001 → Drafts → "Affiche SOLDES Direct"`);
