import { useState, useRef } from "react"; const C = { bg: "#080810", surface: "#0f0f1a", surface2: "#141425", border: "#1e1e32", border2: "#2a2a45", text: "#c8c8e0", dim: "#55556a", accent: "#fb204a", teal: "#00d4aa", gold: "#ffb347", blue: "#61d4ff", white: "#eeeef8", }; const SYMPTOMS = [ { id:"muddy", icon:"🌫️", name:"Suena apagado / embarrado", hint:"Todo suena junto, sin claridad. Los graves dominan." }, { id:"thin", icon:"💨", name:"Suena delgado / sin cuerpo", hint:"La mezcla se escucha flaca, sin peso ni presencia." }, { id:"harsh", icon:"⚡", name:"Suena duro / agresivo", hint:"Duele escuchar. Cansa los oídos. Demasiado agudo." }, { id:"buried", icon:"🪦", name:"La voz se pierde", hint:"El vocal suena bien solo pero desaparece en la mezcla." }, { id:"pumping", icon:"🫀", name:"La mezcla respira / bombea raro", hint:"El volumen sube y baja de forma extraña." }, { id:"nowidth", icon:"📡", name:"Todo suena al centro / mono", hint:"No hay amplitud ni sensación de espacio estéreo." }, { id:"clash", icon:"⚔️", name:"Bombo y bajo chocan", hint:"Cuando entran juntos, se tapan o se oye raro." }, { id:"flat", icon:"📉", name:"Suena plano / sin energía", hint:"Falta emoción, empuje, dimensión." }, { id:"loud", icon:"🔊", name:"No llega al volumen de referencias", hint:"Comparada con canciones comerciales, suena más baja." }, { id:"phase", icon:"🌀", name:"Algo desaparece en mono", hint:"En el teléfono o un parlante, algo se pierde." }, { id:"reverb", icon:"🏛️", name:"Demasiado reverb / suena lejano", hint:"Los elementos suenan en una caverna." }, { id:"nogroove",icon:"🥁", name:"La batería no tiene punch", hint:"El bombo o la caja no golpean. Suenan blandos." }, ]; const GENRES = ["Trap / Hip-Hop","Reggaetón / Urbano","Pop","R&B / Soul","Rock","Electrónica / EDM","Cumbia / Salsa","Balada","Otro"]; const QUICK_QS = [ "¿Puedes explicar más el fix rápido?", "¿Qué plugin me recomiendas?", "¿Cómo aplico esto en mi DAW?", "Dame un ejemplo con un instrumento específico", "¿Cómo suena diferente en monitores vs auriculares?", ]; // ── MARKDOWN FORMATTER ── function formatMd(text) { const lines = text.split("\n"); const out = []; let i = 0; while (i < lines.length) { const line = lines[i]; if (!line.trim()) { i++; continue; } if (/^#{1,3}\s/.test(line)) { out.push(

{inlineFormat(line.replace(/^#{1,3}\s/,""))}

); } else if (/^[-•]\s/.test(line)) { const items = []; while (i < lines.length && /^[-•]\s/.test(lines[i])) { items.push(
  • {inlineFormat(lines[i].replace(/^[-•]\s/,""))}
  • ); i++; } out.push(
      {items}
    ); continue; } else { out.push(

    {inlineFormat(line)}

    ); } i++; } return out; } function inlineFormat(text) { const parts = []; const re = /(\*\*(.+?)\*\*|\*(.+?)\*|`(.+?)`)/g; let last = 0, m; while ((m = re.exec(text)) !== null) { if (m.index > last) parts.push(text.slice(last, m.index)); if (m[2]) parts.push({m[2]}); else if (m[3]) parts.push({m[3]}); else if (m[4]) parts.push({m[4]}); last = m.index + m[0].length; } if (last < text.length) parts.push(text.slice(last)); return parts.length === 1 && typeof parts[0] === "string" ? parts[0] : parts; } // ── LOADING BARS ── function LoadingBars() { const bars = [ {h:20,c:C.accent},{h:32,c:C.gold},{h:44,c:C.accent},{h:28,c:C.teal}, {h:40,c:C.accent},{h:22,c:C.blue},{h:36,c:C.accent},{h:26,c:C.gold},{h:42,c:C.teal} ]; return (
    {bars.map((b,i)=>(
    ))}
    Analizando tu mezcla...
    Consultando con el ingeniero
    ); } // ── MAIN COMPONENT ── export default function MixDoctor() { const [stage, setStage] = useState("symptoms"); // symptoms | loading | result const [selected, setSelected] = useState(new Set()); const [genre, setGenre] = useState(""); const [userNote, setUserNote] = useState(""); const [diagnosis, setDiagnosis] = useState(null); const [thread, setThread] = useState([]); const [followupText, setFollowupText] = useState(""); const [isTyping, setIsTyping] = useState(false); const [showQuick, setShowQuick] = useState(true); const history = useRef([]); const threadRef = useRef(null); function toggleSymptom(id) { setSelected(prev => { const n = new Set(prev); n.has(id) ? n.delete(id) : n.add(id); return n; }); } async function runDiagnosis() { const selectedList = SYMPTOMS.filter(s => selected.has(s.id)).map(s => s.name); const prompt = `Eres Mix Doctor, un ingeniero de mezcla experto que ayuda a productores principiantes e intermedios a diagnosticar y resolver problemas en sus mezclas. Respondes en español, con un tono directo, profesional pero accesible — como un mentor experimentado. El productor describe los siguientes problemas en su mezcla: ${selectedList.map(s=>`• ${s}`).join("\n")} ${userNote ? `\nDescripción adicional: "${userNote}"` : ""} ${genre ? `\nGénero: ${genre}` : ""} Proporciona un diagnóstico completo. Estructura tu respuesta así: **🔍 Diagnóstico Principal** Identifica el problema raíz más probable. Explica por qué ocurre. **🎯 Causas Más Probables** Lista las 3-4 causas más comunes para estos síntomas, ordenadas de más a menos probable. **🛠️ Soluciones Paso a Paso** Instrucciones concretas y específicas. Incluye frecuencias, valores de parámetros, técnicas reales. **⚡ Fix Rápido (5 minutos)** Una sola cosa que puede intentar AHORA MISMO. **📐 Cómo Prevenir Este Problema** Un consejo de flujo de trabajo para futuras mezclas. Sé específico y técnico. Si el género es relevante, adapta los consejos.`; history.current = [{ role:"user", content: prompt }]; setStage("loading"); try { const res = await fetch("https://api.anthropic.com/v1/messages", { method:"POST", headers:{"Content-Type":"application/json"}, body: JSON.stringify({ model:"claude-sonnet-4-20250514", max_tokens:1000, messages: history.current }) }); const data = await res.json(); const text = data.content?.map(b=>b.text||"").join("") || "No se recibió respuesta."; history.current.push({ role:"assistant", content: text }); setDiagnosis({ text, selectedList, genre }); setStage("result"); } catch(e) { setDiagnosis({ text:"Error de conexión. Intenta de nuevo.", selectedList, genre }); setStage("result"); } } async function sendMessage(msg) { if (!msg.trim()) return; setShowQuick(false); setIsTyping(true); setThread(prev => [...prev, { role:"user", content: msg }]); setFollowupText(""); history.current.push({ role:"user", content: msg }); setTimeout(()=> threadRef.current?.scrollIntoView({ behavior:"smooth", block:"end" }), 100); try { const res = await fetch("https://api.anthropic.com/v1/messages", { method:"POST", headers:{"Content-Type":"application/json"}, body: JSON.stringify({ model:"claude-sonnet-4-20250514", max_tokens:1000, messages: history.current }) }); const data = await res.json(); const text = data.content?.map(b=>b.text||"").join("") || "No se recibió respuesta."; history.current.push({ role:"assistant", content: text }); setThread(prev => [...prev, { role:"assistant", content: text }]); } catch(e) { setThread(prev => [...prev, { role:"assistant", content:"Error de conexión. Intenta de nuevo." }]); } setIsTyping(false); setTimeout(()=> threadRef.current?.scrollIntoView({ behavior:"smooth", block:"end" }), 100); } function reset() { setStage("symptoms"); setSelected(new Set()); setGenre(""); setUserNote(""); setDiagnosis(null); setThread([]); setFollowupText(""); setIsTyping(false); setShowQuick(true); history.current = []; } // ── STYLES ── const s = { wrap: { background:C.bg, minHeight:"100vh", fontFamily:"'Open Sans',sans-serif", color:C.text }, header: { padding:"24px 28px 0", borderBottom:`1px solid ${C.border}`, background:"linear-gradient(180deg,#0c0c18,transparent)", display:"flex", justifyContent:"space-between", alignItems:"center", flexWrap:"wrap", gap:10 }, h1: { fontFamily:"Montserrat,sans-serif", fontWeight:900, fontSize:28, color:C.white, letterSpacing:-1, lineHeight:1 }, main: { maxWidth:860, margin:"0 auto", padding:"32px 28px 60px" }, stageLabel: { fontSize:10, letterSpacing:5, color:C.accent, textTransform:"uppercase", marginBottom:10, display:"flex", alignItems:"center", gap:10 }, stageTitle: { fontFamily:"Montserrat,sans-serif", fontWeight:800, fontSize:22, color:C.white, marginBottom:8, letterSpacing:-0.5 }, stageDesc: { fontSize:13, color:C.dim, marginBottom:24, lineHeight:1.7 }, symptomGrid: { display:"grid", gridTemplateColumns:"repeat(auto-fill,minmax(220px,1fr))", gap:8, marginBottom:24 }, symptomBtn: (sel) => ({ background: sel ? `rgba(251,32,74,0.1)` : C.surface, border: `1px solid ${sel ? C.accent : C.border}`, borderRadius:4, padding:"14px 16px", cursor:"pointer", textAlign:"left", transition:"all 0.15s", display:"flex", alignItems:"flex-start", gap:10, width:"100%" }), genreRow: { display:"flex", flexWrap:"wrap", gap:8, marginBottom:24 }, genrePill: (sel) => ({ padding:"6px 14px", borderRadius:20, border:`1px solid ${sel ? C.teal : C.border2}`, background: sel ? "rgba(0,212,170,0.1)" : "transparent", color: sel ? C.teal : C.dim, fontSize:12, fontWeight:600, cursor:"pointer", transition:"all 0.15s", fontFamily:"'Open Sans',sans-serif" }), textarea: { width:"100%", background:C.surface, border:`1px solid ${C.border}`, borderRadius:4, padding:"12px 14px", color:C.white, fontFamily:"'Open Sans',sans-serif", fontSize:13, lineHeight:1.7, resize:"vertical", minHeight:88, outline:"none" }, diagBtn: (dis) => ({ background: dis ? C.border2 : C.accent, color: dis ? C.dim : "#fff", border:"none", borderRadius:4, padding:"14px 32px", fontFamily:"Montserrat,sans-serif", fontWeight:800, fontSize:13, letterSpacing:1, textTransform:"uppercase", cursor: dis ? "not-allowed" : "pointer", display:"flex", alignItems:"center", gap:8, transition:"all 0.2s" }), card: { background:C.surface, border:`1px solid ${C.border}`, borderLeft:`3px solid ${C.accent}`, borderRadius:4, overflow:"hidden", marginBottom:12 }, cardHead: { padding:"12px 20px", background:C.surface2, borderBottom:`1px solid ${C.border}`, fontSize:9, letterSpacing:4, color:C.dim, textTransform:"uppercase", display:"flex", alignItems:"center", gap:8 }, cardBody: { padding:"18px 20px" }, threadMsg: (role) => ({ padding:"14px 18px", borderRadius:4, marginBottom:10, background: C.surface, border:`1px solid ${C.border}`, borderLeft:`3px solid ${role==="user" ? C.gold : C.accent}`, fontSize:13, lineHeight:1.8, color:C.text }), followInput: { flex:1, background:C.surface2, border:`1px solid ${C.border}`, borderRadius:4, padding:"11px 14px", color:C.white, fontFamily:"'Open Sans',sans-serif", fontSize:13, outline:"none" }, followBtn: { background:C.surface2, border:`1px solid ${C.border2}`, borderRadius:4, padding:"11px 18px", color:C.text, fontFamily:"Montserrat,sans-serif", fontWeight:700, fontSize:12, letterSpacing:1, cursor:"pointer" }, resetBtn: { background:"none", border:`1px solid ${C.border2}`, borderRadius:4, padding:"9px 18px", color:C.dim, fontSize:12, fontWeight:600, cursor:"pointer", marginTop:20, fontFamily:"'Open Sans',sans-serif" }, quickBtn: { background:"none", border:`1px solid ${C.border}`, borderRadius:20, padding:"6px 13px", color:C.dim, fontSize:11, cursor:"pointer", fontFamily:"'Open Sans',sans-serif", transition:"all 0.15s" }, }; return (
    {/* HEADER */}
    Herramienta de Diagnóstico
    Mix Doctor
    Juan Manuel Alcantara
    Ingeniero de Mezcla
    {/* ── STAGE: SYMPTOMS ── */} {stage === "symptoms" && (
    Paso 1
    ¿Qué está mal en tu mezcla?
    Selecciona uno o más síntomas que escuchas. Puedes elegir varios.
    {SYMPTOMS.map(sym => ( ))}
    Describe el problema (opcional)