// ===== Casepoint shared UI components =====

function Avatar({ name, initials, hue = 256, size = 32 }){
  const ini = initials || (name||"?").split(" ").map(w=>w[0]).slice(0,2).join("").toUpperCase();
  return (
    <div style={{
      width:size, height:size, borderRadius:"50%", flexShrink:0,
      display:"flex", alignItems:"center", justifyContent:"center",
      fontSize:size*0.36, fontWeight:700, letterSpacing:"0.02em",
      color:`oklch(0.42 0.12 ${hue})`,
      background:`oklch(0.94 0.045 ${hue})`,
      border:`1px solid oklch(0.88 0.05 ${hue})`,
    }}>{ini}</div>
  );
}

const STATUS_VARS = {
  entrada: { fg:"var(--st-entrada)", bg:"var(--st-entrada-soft)" },
  rep:     { fg:"var(--st-rep)",     bg:"var(--st-rep-soft)" },
  listo:   { fg:"var(--st-listo)",   bg:"var(--st-listo-soft)" },
  salida:  { fg:"var(--st-salida)",  bg:"var(--st-salida-soft)" },
};

function StatusBadge({ status, size = "md" }){
  const s = STATUSES[status]; if(!s) return null;
  const v = STATUS_VARS[s.color];
  const pad = size === "sm" ? "3px 9px" : "5px 11px";
  const fs = size === "sm" ? 11.5 : 12.5;
  return (
    <span style={{
      display:"inline-flex", alignItems:"center", gap:6, padding:pad,
      borderRadius:99, fontSize:fs, fontWeight:600, lineHeight:1,
      color:v.fg, background:v.bg, whiteSpace:"nowrap",
    }}>
      <span style={{ width:6, height:6, borderRadius:"50%", background:v.fg }} />
      {s.label}
    </span>
  );
}

const PRIO_COLOR = {
  baja:    "oklch(0.6 0.02 262)",
  normal:  "oklch(0.58 0.13 256)",
  alta:    "oklch(0.7 0.15 60)",
  urgente: "var(--danger)",
};
function PriorityTag({ priority }){
  const p = PRIORITIES[priority]; if(!p) return null;
  const c = PRIO_COLOR[priority];
  return (
    <span style={{
      display:"inline-flex", alignItems:"center", gap:6, fontSize:12.5, fontWeight:600, color:"var(--ink-2)",
    }}>
      <span style={{ width:7, height:7, borderRadius:2, background:c, transform:"rotate(45deg)" }} />
      {p.label}
    </span>
  );
}

function Btn({ children, variant = "primary", size = "md", icon, iconRight, onClick, type = "button", style, disabled, title }){
  const sizes = {
    sm: { padding:"7px 12px", fontSize:13, gap:6, iconSize:15 },
    md: { padding:"9px 16px", fontSize:14, gap:7, iconSize:17 },
    lg: { padding:"12px 20px", fontSize:15, gap:8, iconSize:19 },
  }[size];
  const variants = {
    primary: { background:"var(--accent)", color:"#fff", border:"1px solid var(--accent)", boxShadow:"var(--shadow-sm)" },
    secondary: { background:"var(--surface)", color:"var(--ink)", border:"1px solid var(--line)", boxShadow:"var(--shadow-sm)" },
    ghost: { background:"transparent", color:"var(--ink-2)", border:"1px solid transparent" },
    soft: { background:"var(--accent-soft)", color:"var(--accent-ink)", border:"1px solid transparent" },
    danger: { background:"var(--danger-soft)", color:"var(--danger)", border:"1px solid transparent" },
  }[variant];
  const [hover, setHover] = React.useState(false);
  return (
    <button type={type} onClick={onClick} disabled={disabled} title={title}
      onMouseEnter={()=>setHover(true)} onMouseLeave={()=>setHover(false)}
      style={{
        display:"inline-flex", alignItems:"center", justifyContent:"center", gap:sizes.gap,
        padding:sizes.padding, fontSize:sizes.fontSize, fontWeight:600, borderRadius:10,
        cursor:disabled?"not-allowed":"pointer", opacity:disabled?0.5:1,
        transition:"filter .15s, transform .08s, background .15s, box-shadow .15s",
        filter: hover && !disabled ? "brightness(0.96)" : "none",
        whiteSpace:"nowrap", ...variants, ...style,
      }}
      onMouseDown={e=>e.currentTarget.style.transform="scale(0.98)"}
      onMouseUp={e=>e.currentTarget.style.transform="none"}
    >
      {icon && <Icon name={icon} size={sizes.iconSize} />}
      {children}
      {iconRight && <Icon name={iconRight} size={sizes.iconSize} />}
    </button>
  );
}

function IconBtn({ icon, onClick, title, active, size = 18, badge }){
  const [hover, setHover] = React.useState(false);
  return (
    <button onClick={onClick} title={title}
      onMouseEnter={()=>setHover(true)} onMouseLeave={()=>setHover(false)}
      style={{
        position:"relative", width:38, height:38, borderRadius:10, border:"1px solid transparent",
        background: active ? "var(--accent-soft)" : hover ? "var(--surface-2)" : "transparent",
        color: active ? "var(--accent-ink)" : "var(--ink-2)",
        display:"flex", alignItems:"center", justifyContent:"center", transition:"background .15s, color .15s",
      }}>
      <Icon name={icon} size={size} />
      {badge != null && (
        <span style={{
          position:"absolute", top:5, right:5, minWidth:15, height:15, padding:"0 3px",
          borderRadius:99, background:"var(--danger)", color:"#fff", fontSize:9.5, fontWeight:700,
          display:"flex", alignItems:"center", justifyContent:"center", border:"2px solid var(--surface)",
        }}>{badge}</span>
      )}
    </button>
  );
}

function Card({ children, style, pad = 20, ...rest }){
  return (
    <div {...rest} style={{
      background:"var(--surface)", border:"1px solid var(--line)", borderRadius:"var(--radius)",
      boxShadow:"var(--shadow-sm)", padding:pad, ...style,
    }}>{children}</div>
  );
}

function DeviceIcon({ type, size = 18 }){
  const d = getDevice(type);
  return <Icon name={d.icon} size={size} />;
}

function DeviceGlyph({ type, size = 40, hue }){
  const d = getDevice(type);
  return (
    <div style={{
      width:size, height:size, borderRadius:10, flexShrink:0,
      display:"flex", alignItems:"center", justifyContent:"center",
      background:"var(--surface-2)", border:"1px solid var(--line)", color:"var(--ink-2)",
    }}>
      <Icon name={d.icon} size={size*0.55} />
    </div>
  );
}

function Field({ label, children, hint, required, style }){
  return (
    <label style={{ display:"flex", flexDirection:"column", gap:7, ...style }}>
      <span style={{ fontSize:13, fontWeight:600, color:"var(--ink-2)" }}>
        {label}{required && <span style={{ color:"var(--danger)", marginLeft:3 }}>*</span>}
      </span>
      {children}
      {hint && <span style={{ fontSize:12, color:"var(--faint)" }}>{hint}</span>}
    </label>
  );
}

const inputStyle = {
  width:"100%", padding:"10px 12px", fontSize:14, color:"var(--ink)",
  background:"var(--surface)", border:"1px solid var(--line)", borderRadius:10,
  outline:"none", transition:"border-color .15s, box-shadow .15s",
};
function TextInput(props){
  const [f, setF] = React.useState(false);
  return <input {...props} onFocus={e=>{setF(true);props.onFocus&&props.onFocus(e);}} onBlur={e=>{setF(false);props.onBlur&&props.onBlur(e);}}
    style={{ ...inputStyle, borderColor: f ? "var(--accent)" : "var(--line)", boxShadow: f ? "0 0 0 3px var(--accent-soft)" : "none", ...props.style }} />;
}

// Striped placeholder for images the user should provide
function Placeholder({ label, w = "100%", h = 80, style }){
  return (
    <div style={{
      width:w, height:h, borderRadius:10, border:"1px dashed var(--line)",
      background:"repeating-linear-gradient(45deg, var(--surface-2), var(--surface-2) 8px, transparent 8px, transparent 16px)",
      display:"flex", alignItems:"center", justifyContent:"center", color:"var(--faint)",
      fontFamily:"var(--mono)", fontSize:11, textAlign:"center", padding:8, ...style,
    }}>{label}</div>
  );
}

function Sparkbars({ values, color = "var(--accent)", h = 36 }){
  const max = Math.max(...values, 1);
  return (
    <div style={{ display:"flex", alignItems:"flex-end", gap:4, height:h }}>
      {values.map((v,i)=>(
        <div key={i} style={{ flex:1, height:`${Math.max(8,(v/max)*100)}%`, background: i===values.length-1?color:"var(--line)", borderRadius:3, transition:"height .3s" }} />
      ))}
    </div>
  );
}

// ===== Unlock credential (PIN / password / pattern) =====
function PatternLock({ value = [], onChange, size = 168, readOnly = false }){
  const dots = [0,1,2,3,4,5,6,7,8];
  const gap = size / 3;
  const pos = (i) => ({ x: gap*(i%3) + gap/2, y: gap*Math.floor(i/3) + gap/2 });
  function toggle(i){
    if(readOnly) return;
    onChange(value.includes(i) ? value.filter(x=>x!==i) : [...value, i]);
  }
  return (
    <div style={{ position:"relative", width:size, height:size, userSelect:"none" }}>
      <svg width={size} height={size} style={{ position:"absolute", inset:0, pointerEvents:"none" }}>
        {value.slice(1).map((i,idx)=>{
          const a = pos(value[idx]); const b = pos(i);
          return <line key={idx} x1={a.x} y1={a.y} x2={b.x} y2={b.y} stroke="var(--accent)" strokeWidth={3} strokeLinecap="round" opacity={0.65} />;
        })}
      </svg>
      {dots.map(i=>{
        const on = value.includes(i); const order = value.indexOf(i)+1;
        const p = pos(i);
        return (
          <button key={i} type="button" onClick={()=>toggle(i)} disabled={readOnly}
            style={{ position:"absolute", left:p.x-gap/2, top:p.y-gap/2, width:gap, height:gap, border:"none", background:"transparent", cursor:readOnly?"default":"pointer", display:"flex", alignItems:"center", justifyContent:"center" }}>
            <span style={{ width: on?26:16, height: on?26:16, borderRadius:"50%", display:"flex", alignItems:"center", justifyContent:"center",
              background: on?"var(--accent)":"var(--line)", color:"#fff", fontSize:12, fontWeight:700, transition:"all .12s",
              boxShadow: on?"0 0 0 5px var(--accent-soft)":"none" }}>{on?order:""}</span>
          </button>
        );
      })}
    </div>
  );
}

function UnlockField({ value, onChange }){
  // value: { type:'none'|'code'|'pattern', code:'', pattern:[] }
  const v = value || { type:"none", code:"", pattern:[] };
  const set = (patch) => onChange({ ...v, ...patch });
  const TYPES = [["none","Sin bloqueo"],["code","PIN / Contraseña"],["pattern","Patrón"]];
  return (
    <div>
      <div style={{ display:"flex", gap:8, marginBottom: v.type==="none"?0:14 }}>
        {TYPES.map(([id,l])=>{
          const sel = v.type===id;
          return (
            <button key={id} type="button" onClick={()=>set({ type:id })}
              style={{ flex:1, padding:"9px 8px", borderRadius:9, fontSize:13, fontWeight:600, cursor:"pointer",
                border:`1px solid ${sel?"var(--accent)":"var(--line)"}`, background: sel?"var(--accent-soft)":"var(--surface)", color: sel?"var(--accent-ink)":"var(--ink-2)" }}>{l}</button>
          );
        })}
      </div>
      {v.type==="code" && (
        <TextInput value={v.code} onChange={e=>set({ code:e.target.value })} placeholder="ej. 1234 o contraseña del equipo" style={{ fontFamily:"var(--mono)" }} />
      )}
      {v.type==="pattern" && (
        <div style={{ display:"flex", alignItems:"center", gap:18, padding:"10px 4px" }}>
          <PatternLock value={v.pattern} onChange={p=>set({ pattern:p })} />
          <div style={{ fontSize:12.5, color:"var(--muted)", lineHeight:1.5 }}>
            Toca los puntos en el<br/>orden del patrón.
            {v.pattern.length>0 && <div style={{ marginTop:10 }}><button type="button" onClick={()=>set({ pattern:[] })} style={{ border:"none", background:"transparent", color:"var(--accent-ink)", fontSize:12.5, fontWeight:600, padding:0 }}>Limpiar patrón</button></div>}
          </div>
        </div>
      )}
    </div>
  );
}

// read-only summary used in order detail
function UnlockSummary({ unlock }){
  const u = unlock || { type:"none" };
  const [show, setShow] = React.useState(false);
  if(u.type==="none" || (u.type==="code" && !u.code) || (u.type==="pattern" && !(u.pattern||[]).length)){
    return <span style={{ fontSize:13.5, fontWeight:600, color:"var(--faint)" }}>Sin bloqueo</span>;
  }
  return (
    <div style={{ display:"flex", flexDirection:"column", alignItems:"flex-end", gap:6 }}>
      {!show ? (
        <button type="button" onClick={()=>setShow(true)} style={{ display:"inline-flex", alignItems:"center", gap:6, border:"1px solid var(--line)", background:"var(--surface-2)", borderRadius:8, padding:"5px 10px", fontSize:12.5, fontWeight:600, color:"var(--ink-2)" }}>
          <Icon name="eye" size={15} /> Mostrar {u.type==="pattern"?"patrón":"código"}
        </button>
      ) : u.type==="code" ? (
        <span className="mono" style={{ fontSize:15, fontWeight:700, letterSpacing:"0.06em" }}>{u.code}</span>
      ) : (
        <PatternLock value={u.pattern} readOnly size={104} />
      )}
    </div>
  );
}

// Photo upload slot — reads file as base64 for demo persistence
function PhotoSlot({ label, value, onChange, h = 86 }){
  const inputRef = React.useRef(null);
  function pick(e){
    const file = e.target.files && e.target.files[0];
    if(!file) return;
    if(!file.type.startsWith("image/")){ return; }
    const reader = new FileReader();
    reader.onload = () => {
      // downscale to keep localStorage small
      const img = new Image();
      img.onload = () => {
        const max = 900;
        let { width, height } = img;
        if(width > max || height > max){ const r = Math.min(max/width, max/height); width = Math.round(width*r); height = Math.round(height*r); }
        const cv = document.createElement("canvas"); cv.width = width; cv.height = height;
        cv.getContext("2d").drawImage(img, 0, 0, width, height);
        // En modo online sube la foto a R2 y guarda la URL; offline guarda base64.
        if(window.CP_API && CP_API.online && cv.toBlob){
          cv.toBlob(async (blob)=>{
            const url = blob ? await CP_API.uploadPhoto(blob) : null;
            onChange(url || cv.toDataURL("image/jpeg", 0.72));
          }, "image/jpeg", 0.72);
        } else {
          onChange(cv.toDataURL("image/jpeg", 0.72));
        }
      };
      img.src = reader.result;
    };
    reader.readAsDataURL(file);
  }
  return (
    <div style={{ position:"relative" }}>
      <input ref={inputRef} type="file" accept="image/*" onChange={pick} style={{ display:"none" }} />
      {value ? (
        <div style={{ position:"relative", height:h, borderRadius:10, overflow:"hidden", border:"1px solid var(--line)" }}>
          <img src={value} alt={label} style={{ width:"100%", height:"100%", objectFit:"cover", display:"block" }} />
          <div style={{ position:"absolute", left:0, right:0, bottom:0, padding:"3px 7px", fontSize:10.5, fontWeight:600, color:"#fff", background:"linear-gradient(transparent, oklch(0.2 0.03 262 / 0.7))" }}>{label}</div>
          <button type="button" onClick={()=>onChange("")} title="Quitar"
            style={{ position:"absolute", top:4, right:4, width:22, height:22, borderRadius:"50%", border:"none", background:"oklch(0.2 0.03 262 / 0.6)", color:"#fff", display:"flex", alignItems:"center", justifyContent:"center", cursor:"pointer" }}>
            <Icon name="x" size={13} />
          </button>
        </div>
      ) : (
        <button type="button" onClick={()=>inputRef.current && inputRef.current.click()}
          style={{ width:"100%", height:h, borderRadius:10, border:"1px dashed var(--line)", background:"var(--surface-2)", cursor:"pointer",
            display:"flex", flexDirection:"column", alignItems:"center", justifyContent:"center", gap:4, color:"var(--faint)", transition:"border-color .14s, color .14s" }}
          onMouseEnter={e=>{ e.currentTarget.style.borderColor="var(--accent)"; e.currentTarget.style.color="var(--accent-ink)"; }}
          onMouseLeave={e=>{ e.currentTarget.style.borderColor="var(--line)"; e.currentTarget.style.color="var(--faint)"; }}>
          <Icon name="camera" size={20} />
          <span style={{ fontSize:11, fontWeight:600 }}>{label}</span>
        </button>
      )}
    </div>
  );
}

Object.assign(window, {
  Avatar, StatusBadge, PriorityTag, Btn, IconBtn, Card, DeviceIcon, DeviceGlyph,
  Field, TextInput, inputStyle, Placeholder, Sparkbars, PRIO_COLOR, STATUS_VARS,
  PatternLock, UnlockField, UnlockSummary, PhotoSlot,
});
