const createDOMPurify = require('dompurify');
const express = require('express');
const crypto = require('crypto');
const { JSDOM } = require('jsdom');
const path = require('path');
const fs = require('fs');

const app = express();
const PORT = 8000;

app.use((req, res, next) => {
    res.locals.nonce = crypto.randomBytes(16).toString('base64');
    res.setHeader('Content-Security-Policy', [
        "default-src 'none'",
        `script-src 'nonce-${res.locals.nonce}' 'strict-dynamic'`,
        "style-src 'self' 'unsafe-inline'",
        "font-src 'self'",
        "img-src 'self' data:",
        "connect-src 'self'",
        "form-action 'none'",
        "frame-ancestors 'none'"
    ].join('; '));
    res.setHeader('X-Frame-Options', 'DENY');
    res.setHeader('cross-origin-opener-policy', 'same-origin');
    next();
});
app.use(express.json());
app.use(express.static(path.join(__dirname, 'public'), { index: false }));

// Fish customization options
const options = {
    body: [
        { name: 'Classic', path: 'M80,100 Q120,60 200,70 Q260,75 280,100 Q260,125 200,130 Q120,140 80,100 Z' },
        { name: 'Chubby', path: 'M80,100 Q100,50 180,55 Q260,60 290,100 Q260,140 180,145 Q100,150 80,100 Z' },
        { name: 'Slim', path: 'M90,100 Q130,75 200,80 Q250,82 270,100 Q250,118 200,120 Q130,125 90,100 Z' },
        { name: 'Puffer', path: 'M70,100 Q90,40 180,45 Q270,50 295,100 Q270,150 180,155 Q90,160 70,100 Z' },
        { name: 'Flat', path: 'M85,100 Q120,80 200,85 Q255,87 275,100 Q255,113 200,115 Q120,120 85,100 Z' }
    ],
    eyes: [
        { name: 'Normal', render: (color) => `<circle cx="230" cy="90" r="15" fill="white"/><circle cx="233" cy="90" r="8" fill="#1a1a2e"/><circle cx="236" cy="87" r="3" fill="white"/>` },
        { name: 'Big', render: (color) => `<circle cx="230" cy="88" r="22" fill="white"/><circle cx="235" cy="88" r="12" fill="#1a1a2e"/><circle cx="240" cy="84" r="5" fill="white"/>` },
        { name: 'Sleepy', render: (color) => `<ellipse cx="230" cy="90" rx="15" ry="8" fill="white"/><ellipse cx="233" cy="90" rx="6" ry="5" fill="#1a1a2e"/><path d="M215,82 Q230,78 245,82" stroke="#1a1a2e" stroke-width="2" fill="none"/>` },
        { name: 'Happy', render: (color) => `<path d="M215,90 Q230,80 245,90" stroke="#1a1a2e" stroke-width="4" fill="none" stroke-linecap="round"/><circle cx="237" cy="87" r="3" fill="white"/>` },
        { name: 'Derp', render: (color) => `<circle cx="225" cy="85" r="12" fill="white"/><circle cx="240" cy="95" r="10" fill="white"/><circle cx="228" cy="85" r="6" fill="#1a1a2e"/><circle cx="243" cy="95" r="5" fill="#1a1a2e"/>` },
        { name: 'Angry', render: (color) => `<circle cx="230" cy="90" r="14" fill="white"/><circle cx="233" cy="92" r="8" fill="#8b0000"/><circle cx="236" cy="89" r="3" fill="white"/><path d="M215,78 L245,88" stroke="#1a1a2e" stroke-width="3"/>` }
    ],
    fins: [
        { name: 'Standard', render: (color) => `<path d="M160,70 Q170,40 190,55 Q175,65 170,70" fill="${color}" opacity="0.8"/><path d="M160,130 Q170,160 190,145 Q175,135 170,130" fill="${color}" opacity="0.8"/>` },
        { name: 'Spiky', render: (color) => `<path d="M150,70 L165,30 L175,60 L185,25 L190,65" fill="${color}" opacity="0.8"/><path d="M150,130 L165,170 L175,140 L185,175 L190,135" fill="${color}" opacity="0.8"/>` },
        { name: 'Flowing', render: (color) => `<path d="M140,75 Q180,20 220,50 Q180,55 155,72" fill="${color}" opacity="0.7"/><path d="M140,125 Q180,180 220,150 Q180,145 155,128" fill="${color}" opacity="0.7"/>` },
        { name: 'Tiny', render: (color) => `<path d="M175,75 Q185,60 195,70" fill="${color}" opacity="0.8"/><path d="M175,125 Q185,140 195,130" fill="${color}" opacity="0.8"/>` },
        { name: 'Wave', render: (color) => `<path d="M145,72 Q160,50 170,60 Q180,45 195,65" fill="${color}" opacity="0.8"/><path d="M145,128 Q160,150 170,140 Q180,155 195,135" fill="${color}" opacity="0.8"/>` }
    ],
    tail: [
        { name: 'Fan', render: (color) => `<path d="M80,100 Q40,60 20,40 Q50,80 50,100 Q50,120 20,160 Q40,140 80,100" fill="${color}"/>` },
        { name: 'Forked', render: (color) => `<path d="M80,100 L40,50 Q55,80 60,100 Q55,120 40,150 L80,100" fill="${color}"/>` },
        { name: 'Round', render: (color) => `<path d="M80,100 Q30,70 25,100 Q30,130 80,100" fill="${color}"/>` },
        { name: 'Spear', render: (color) => `<path d="M80,100 L20,95 L30,100 L20,105 L80,100" fill="${color}"/>` },
        { name: 'Fancy', render: (color) => `<path d="M80,100 Q50,50 15,30 Q40,70 45,100 Q40,130 15,170 Q50,150 80,100" fill="${color}"/><path d="M60,100 Q40,75 25,70 Q45,90 50,100 Q45,110 25,130 Q40,125 60,100" fill="${color}" opacity="0.6"/>` },
        { name: 'Ribbon', render: (color) => `<path d="M80,100 Q60,60 30,50 Q50,80 55,100 Q50,120 30,150 Q60,140 80,100" fill="${color}"/><path d="M55,100 Q45,85 35,80" stroke="${color}" stroke-width="3" fill="none" opacity="0.5"/><path d="M55,100 Q45,115 35,120" stroke="${color}" stroke-width="3" fill="none" opacity="0.5"/>` }
    ],
    pattern: [
        { name: 'None', render: () => '' },
        { name: 'Stripes', render: () => `<g opacity="0.3"><path d="M130,75 L140,125" stroke="white" stroke-width="8"/><path d="M160,72 L170,128" stroke="white" stroke-width="8"/><path d="M190,73 L200,127" stroke="white" stroke-width="8"/></g>` },
        { name: 'Spots', render: () => `<g opacity="0.4"><circle cx="140" cy="95" r="8" fill="white"/><circle cx="170" cy="105" r="6" fill="white"/><circle cx="200" cy="90" r="7" fill="white"/><circle cx="155" cy="115" r="5" fill="white"/></g>` },
        { name: 'Scales', render: () => `<g opacity="0.2"><path d="M120,90 Q130,85 140,90 Q130,95 120,90" fill="white"/><path d="M140,90 Q150,85 160,90 Q150,95 140,90" fill="white"/><path d="M160,90 Q170,85 180,90 Q170,95 160,90" fill="white"/><path d="M130,105 Q140,100 150,105 Q140,110 130,105" fill="white"/><path d="M150,105 Q160,100 170,105 Q160,110 150,105" fill="white"/><path d="M170,105 Q180,100 190,105 Q180,110 170,105" fill="white"/></g>` },
        { name: 'Gradient', render: () => `<defs><linearGradient id="bodyGrad" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" style="stop-color:white;stop-opacity:0.3"/><stop offset="100%" style="stop-color:white;stop-opacity:0"/></linearGradient></defs><path d="M80,100 Q120,60 200,70 Q260,75 280,100 Q260,125 200,130 Q120,140 80,100 Z" fill="url(#bodyGrad)"/>` },
        { name: 'Stars', render: () => `<g opacity="0.5" fill="#ffd700"><polygon points="145,95 147,90 152,90 148,86 150,81 145,84 140,81 142,86 138,90 143,90"/><polygon points="175,100 177,95 182,95 178,91 180,86 175,89 170,86 172,91 168,95 173,95" transform="scale(0.8) translate(35,15)"/><polygon points="195,88 197,83 202,83 198,79 200,74 195,77 190,74 192,79 188,83 193,83" transform="scale(0.7) translate(85,35)"/></g>` }
    ],
    color: [
        { name: 'Ocean Blue', value: '#5bc0eb' },
        { name: 'Coral Pink', value: '#ff6b9d' },
        { name: 'Sunset Orange', value: '#ff9f43' },
        { name: 'Seaweed Green', value: '#00d4aa' },
        { name: 'Royal Purple', value: '#a55eea' },
        { name: 'Golden', value: '#ffc857' },
        { name: 'Crimson', value: '#e74c3c' },
        { name: 'Midnight', value: '#2c3e50' },
        { name: 'Rainbow', value: 'url(#rainbow)' }
    ],
    accessory: [
        { name: 'None', render: () => '' },
        { name: 'Crown', render: () => `<g transform="translate(210, 45)"><polygon points="15,25 0,10 8,15 15,0 22,15 30,10 15,25" fill="#ffd700"/><circle cx="15" cy="8" r="3" fill="#e74c3c"/></g>` },
        { name: 'Hat', render: () => `<g transform="translate(200, 40)"><ellipse cx="25" cy="30" rx="25" ry="5" fill="#2c3e50"/><rect x="10" y="10" width="30" height="20" rx="3" fill="#2c3e50"/><rect x="5" y="25" width="40" height="8" rx="2" fill="#34495e"/></g>` },
        { name: 'Bow', render: () => `<g transform="translate(245, 75)"><ellipse cx="0" cy="0" rx="12" ry="8" fill="#ff6b9d" transform="rotate(-30)"/><ellipse cx="15" cy="5" rx="12" ry="8" fill="#ff6b9d" transform="rotate(30)"/><circle cx="8" cy="3" r="5" fill="#e74c3c"/></g>` },
        { name: 'Monocle', render: () => `<g transform="translate(220, 80)"><circle cx="15" cy="10" r="12" fill="none" stroke="#ffd700" stroke-width="2"/><line x1="27" y1="15" x2="40" y2="40" stroke="#ffd700" stroke-width="1.5"/><circle cx="15" cy="10" r="8" fill="rgba(200,230,255,0.3)"/></g>` },
        { name: 'Bubbles', render: () => `<g opacity="0.7"><circle cx="270" cy="70" r="5" fill="none" stroke="rgba(255,255,255,0.6)" stroke-width="1"/><circle cx="285" cy="55" r="8" fill="none" stroke="rgba(255,255,255,0.5)" stroke-width="1"/><circle cx="295" cy="75" r="4" fill="none" stroke="rgba(255,255,255,0.7)" stroke-width="1"/></g>` },
        { name: 'Sparkles', render: () => `<g fill="#ffd700" opacity="0.8"><polygon points="265,60 267,55 272,55 268,51 270,46 265,49 260,46 262,51 258,55 263,55"/><polygon points="280,80 281,77 284,77 282,75 283,72 280,74 277,72 278,75 276,77 279,77" transform="scale(0.7) translate(120,35)"/><polygon points="290,55 291,52 294,52 292,50 293,47 290,49 287,47 288,50 286,52 289,52" transform="scale(0.6) translate(195,30)"/></g>` }
    ]
};

// Render fish SVG from configuration using JSDOM
function renderFish(config) {
    const { body, eyes, fins, tail, pattern, color, accessory, name } = config;

    // Validate indices
    const bodyIdx = Math.max(0, Math.min(body || 0, options.body.length - 1));
    const eyesIdx = Math.max(0, Math.min(eyes || 0, options.eyes.length - 1));
    const finsIdx = Math.max(0, Math.min(fins || 0, options.fins.length - 1));
    const tailIdx = Math.max(0, Math.min(tail || 0, options.tail.length - 1));
    const patternIdx = Math.max(0, Math.min(pattern || 0, options.pattern.length - 1));
    const accessoryIdx = Math.max(0, Math.min(accessory || 0, options.accessory.length - 1));
    const colorIdx = Math.max(0, Math.min(color || 0, options.color.length - 1));

    const colorValue = isNaN(color) ? color : options.color[colorIdx]?.value;
    const bodyPath = options.body[bodyIdx].path;
    const animatedBodyPath = bodyPath.replace(/Q(\d+),(\d+)/g, (m, x, y) => `Q${x},${parseInt(y) + 2}`);

    // Create DOM
    const window = new JSDOM('<!DOCTYPE html><html><body></body></html>').window;
    const document = window.document;
    const createHTML = (tag) => document.createElement(tag);
    const createSVG = (tag) => document.createElementNS('http://www.w3.org/2000/svg', tag);

    // Fish root element (metadata)
    const fishRoot = createHTML(name || 'unnamed-fish');
    fishRoot.setAttribute('body', options.body[bodyIdx].name);
    fishRoot.setAttribute('eyes', options.eyes[eyesIdx].name);
    fishRoot.setAttribute('fins', options.fins[finsIdx].name);
    fishRoot.setAttribute('tail', options.tail[tailIdx].name);
    fishRoot.setAttribute('pattern', options.pattern[patternIdx].name);
    fishRoot.setAttribute('color-value', colorValue);
    fishRoot.setAttribute('accessory', options.accessory[accessoryIdx].name);

    // SVG root
    const svg = createSVG('svg');
    svg.setAttribute('viewBox', '0 0 320 200');
    svg.setAttribute('width', '320');
    svg.setAttribute('height', '200');
    fishRoot.appendChild(svg);

    // Rainbow gradient
    const defs = createSVG('defs');
    defs.innerHTML = `<linearGradient id="rainbow" x1="0%" y1="0%" x2="100%" y2="0%">
        <stop offset="0%" style="stop-color:#ff6b6b"/>
        <stop offset="25%" style="stop-color:#ffd93d"/>
        <stop offset="50%" style="stop-color:#6bcb77"/>
        <stop offset="75%" style="stop-color:#4d96ff"/>
        <stop offset="100%" style="stop-color:#a55eea"/>
    </linearGradient>`;
    svg.appendChild(defs);

    // Tail
    const tailG = createSVG('g');
    tailG.innerHTML = options.tail[tailIdx].render(colorValue);
    svg.appendChild(tailG);

    // Body
    const bodyEl = createSVG('path');
    bodyEl.setAttribute('d', bodyPath);
    bodyEl.setAttribute('fill', colorValue);
    const animate = createSVG('animate');
    animate.setAttribute('attributeName', 'd');
    animate.setAttribute('dur', '2s');
    animate.setAttribute('repeatCount', 'indefinite');
    animate.setAttribute('values', `${bodyPath};${animatedBodyPath};${bodyPath}`);
    bodyEl.appendChild(animate);
    svg.appendChild(bodyEl);

    // Pattern
    const patternG = createSVG('g');
    patternG.innerHTML = options.pattern[patternIdx].render();
    svg.appendChild(patternG);

    // Fins
    const finsG = createSVG('g');
    finsG.innerHTML = options.fins[finsIdx].render(colorValue);
    svg.appendChild(finsG);

    // Eyes
    const eyesG = createSVG('g');
    eyesG.innerHTML = options.eyes[eyesIdx].render();
    svg.appendChild(eyesG);

    // Mouth
    const mouth = createSVG('ellipse');
    mouth.setAttribute('cx', '275');
    mouth.setAttribute('cy', '105');
    mouth.setAttribute('rx', '4');
    mouth.setAttribute('ry', '3');
    mouth.setAttribute('fill', '#1a1a2e');
    mouth.setAttribute('opacity', '0.5');
    svg.appendChild(mouth);

    // Accessory
    const accessoryG = createSVG('g');
    accessoryG.innerHTML = options.accessory[accessoryIdx].render();
    svg.appendChild(accessoryG);

    const DOMPurify = createDOMPurify(window);
    return DOMPurify.sanitize(fishRoot, {
        ADD_ATTR: ['body', 'eyes', 'fins', 'tail', 'pattern', 'color', 'color-value', 'accessory'],
        ADD_TAGS: ['animate'],
        CUSTOM_ELEMENT_HANDLING: {
            tagNameCheck: /^(Captain|Sir|Lady|Professor|Duke|Princess|Lord|Admiral|Baron|Count)-/i
        }
    });
}

// API endpoint to render fish
app.post('/api/fish', (req, res) => {
    const config = req.body;
    const html = renderFish(config);
    res.send(html);
});

// Get options metadata (names and counts)
app.get('/api/options', (req, res) => {
    const metadata = {};
    for (const [key, value] of Object.entries(options)) {
        metadata[key] = value.map(opt => opt.name || opt.value);
    }
    res.json(metadata);
});

app.get('/', (req, res) => {
    const htmlPath = path.join(__dirname, 'public', 'index.html');
    let html = fs.readFileSync(htmlPath, 'utf8');
    html = html.replace('<script src="app.js">', `<script nonce="${res.locals.nonce}" src="app.js">`);
    res.send(html);
});

app.listen(PORT, '0.0.0.0', () => {
    console.log(`🐟 Fish Customizer running at http://0.0.0.0:${PORT}`);
});
