// Componentes de campos del formulario público
const { useState: useStateFF, useRef: useRefFF, useEffect: useEffectFF } = React;

function Field({ id, label, required, optional, hint, error, valid, children, span }) {
  return (
    <div className={'gf-field' + (error ? ' is-invalid' : valid ? ' is-valid' : '')} style={span ? { gridColumn: '1 / -1' } : null}>
      <label htmlFor={id} className="gf-label">
        {label}
        {required && <span className="gf-req" aria-hidden="true">*</span>}
        {optional && <span className="gf-opt">{optional}</span>}
      </label>
      <div className="gf-control">
        {children}
        {valid && !error && <span className="gf-ok" aria-hidden="true"><Icon name="check" size={16} stroke={2.6} /></span>}
      </div>
      {error ? (
        <p className="gf-error" id={id + '-err'} role="alert"><Icon name="alert" size={15} /> {error}</p>
      ) : hint ? (
        <p className="gf-hint" id={id + '-hint'}>{hint}</p>
      ) : null}
    </div>
  );
}

const COUNTRY_CODES = [
  { c: '+506', n: 'CR' }, { c: '+505', n: 'NI' }, { c: '+507', n: 'PA' },
  { c: '+503', n: 'SV' }, { c: '+504', n: 'HN' }, { c: '+502', n: 'GT' },
  { c: '+52', n: 'MX' }, { c: '+57', n: 'CO' }, { c: '+58', n: 'VE' },
  { c: '+1', n: 'US/CA' }, { c: '+34', n: 'ES' },
];

function PhoneInput({ id, code, value, onCode, onChange, onBlur, invalid }) {
  return (
    <div className="gf-phone">
      <select className="select gf-phone-code" aria-label="Código de país" value={code} onChange={e => onCode(e.target.value)}>
        {COUNTRY_CODES.map(x => <option key={x.c} value={x.c}>{x.n} {x.c}</option>)}
      </select>
      <input id={id} className="input" type="tel" inputMode="numeric" autoComplete="tel-national"
        placeholder={code === '+506' ? '8888 8888' : 'Número'}
        value={value} onChange={e => onChange(e.target.value.replace(/[^0-9]/g, '').slice(0, 14))} onBlur={onBlur}
        aria-invalid={invalid || undefined} aria-describedby={invalid ? id + '-err' : undefined} />
    </div>
  );
}

// --------- Carga de archivos ---------
const FILE_RULES = { maxMB: 5, types: ['application/pdf', 'image/jpeg', 'image/png'], ext: ['pdf', 'jpg', 'jpeg', 'png'] };

function makeThumb(file) {
  return new Promise((resolve) => {
    if (!file.type.startsWith('image/')) return resolve(null);
    const fr = new FileReader();
    fr.onload = () => {
      const img = new Image();
      img.onload = () => {
        const max = 360, s = Math.min(1, max / Math.max(img.width, img.height));
        const c = document.createElement('canvas'); c.width = Math.round(img.width * s); c.height = Math.round(img.height * s);
        c.getContext('2d').drawImage(img, 0, 0, c.width, c.height);
        resolve(c.toDataURL('image/jpeg', 0.72));
      };
      img.onerror = () => resolve(null);
      img.src = fr.result;
    };
    fr.onerror = () => resolve(null);
    fr.readAsDataURL(file);
  });
}

function FileDrop({ id, title, desc, required, badge, value, onChange, error }) {
  const [drag, setDrag] = useStateFF(false);
  const [busy, setBusy] = useStateFF(false);
  const [localErr, setLocalErr] = useStateFF('');
  const input = useRefFF();

  async function accept(file) {
    setLocalErr('');
    if (!file) return;
    const ext = (file.name.split('.').pop() || '').toLowerCase();
    if (!FILE_RULES.types.includes(file.type) && !FILE_RULES.ext.includes(ext)) {
      setLocalErr(`"${file.name}" no es un formato permitido. Usá PDF, JPG o PNG.`); return;
    }
    if (file.size > FILE_RULES.maxMB * 1024 * 1024) {
      setLocalErr(`El archivo pesa ${GFmt.bytes(file.size)}. El máximo permitido es ${FILE_RULES.maxMB} MB.`); return;
    }
    if (file.size === 0) { setLocalErr('El archivo está vacío. Probá con otro.'); return; }
    setBusy(true);
    const thumb = await makeThumb(file);
    setBusy(false);
    onChange({ name: file.name, size: file.size, type: file.type || (ext === 'pdf' ? 'application/pdf' : 'image/' + ext), thumb });
  }

  const err = localErr || error;
  const isPdf = value && (value.type === 'application/pdf' || /\.pdf$/i.test(value.name));

  return (
    <div className={'gf-file' + (value ? ' has-file' : '') + (err ? ' is-invalid' : '')}>
      <div className="gf-file-head">
        <div>
          <div className="gf-file-title">
            {title}{required && <span className="gf-req" aria-hidden="true">*</span>}
            {badge && <span className="gf-file-badge">{badge}</span>}
          </div>
          <p className="gf-file-desc">{desc}</p>
        </div>
        {value && <span className="gf-file-status"><Icon name="check" size={14} stroke={2.8} /> Adjuntado</span>}
      </div>

      {value ? (
        <div className="gf-file-preview">
          <div className="gf-file-thumb">
            {value.thumb ? <img src={value.thumb} alt={'Vista previa de ' + value.name} /> :
              <div className="gf-file-pdf"><Icon name="file" size={26} /><span>{isPdf ? 'PDF' : 'IMG'}</span></div>}
          </div>
          <div className="gf-file-meta">
            <div className="gf-file-name" title={value.name}>{value.name}</div>
            <div className="gf-file-size">{GFmt.bytes(value.size)} · {isPdf ? 'Documento PDF' : 'Imagen'}</div>
            <div className="gf-file-actions">
              <button type="button" className="btn btn-text btn-sm" onClick={() => input.current.click()}><Icon name="refresh" size={16} /> Reemplazar</button>
              <button type="button" className="btn btn-text btn-sm gf-remove" onClick={() => { onChange(null); setLocalErr(''); }}><Icon name="trash" size={16} /> Quitar</button>
            </div>
          </div>
        </div>
      ) : (
        <button type="button" id={id}
          className={'gf-drop' + (drag ? ' is-drag' : '')}
          onClick={() => input.current.click()}
          onDragOver={e => { e.preventDefault(); setDrag(true); }}
          onDragLeave={() => setDrag(false)}
          onDrop={e => { e.preventDefault(); setDrag(false); accept(e.dataTransfer.files[0]); }}
          aria-describedby={err ? id + '-err' : undefined}>
          <span className="gf-drop-icon">{busy ? <span className="gf-spin" /> : <Icon name="upload" size={22} />}</span>
          <span className="gf-drop-main"><strong>Seleccioná un archivo</strong><span className="gf-drop-or"> o arrastralo aquí</span></span>
          <span className="gf-drop-sub">PDF, JPG o PNG · máximo {FILE_RULES.maxMB} MB</span>
        </button>
      )}
      <input ref={input} type="file" accept=".pdf,.jpg,.jpeg,.png,application/pdf,image/jpeg,image/png" hidden
        onChange={e => { accept(e.target.files[0]); e.target.value = ''; }} />
      {err && <p className="gf-error" id={id + '-err'} role="alert"><Icon name="alert" size={15} /> {err}</p>}
    </div>
  );
}

Object.assign(window, { Field, PhoneInput, FileDrop, COUNTRY_CODES });
