// Author: Simon-Pierre Boucher
// Contact: contact@spboucher.ai
// Project: chat.spboucher.ai

"use client";

import { useRef, useState } from "react";
import { estimateTokensClient, formatTokens, perMillion, providerGlyph, type ApiModel } from "./types";

interface ComposerProps {
  model: ApiModel | null;
  contextTokens: number;
  streaming: boolean;
  onSend: (content: string) => void;
  onStop: () => void;
  onOpenModelSheet: () => void;
}

export function Composer({ model, contextTokens, streaming, onSend, onStop, onOpenModelSheet }: ComposerProps) {
  const [text, setText] = useState("");
  const taRef = useRef<HTMLTextAreaElement>(null);

  const totalTokens = contextTokens + estimateTokensClient(text);
  const ctxLimit = model?.contextLength;
  const ctxPct = ctxLimit ? Math.min((totalTokens / ctxLimit) * 100, 100) : 0;

  const send = () => {
    const content = text.trim();
    if (!content || streaming || !model) return;
    setText("");
    if (taRef.current) taRef.current.style.height = "auto";
    onSend(content);
  };

  const onKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
    // Enter sends on desktop; on touch keyboards Enter makes a newline.
    if (e.key === "Enter" && !e.shiftKey && !isTouchDevice()) {
      e.preventDefault();
      send();
    }
  };

  const autoGrow = () => {
    const ta = taRef.current;
    if (!ta) return;
    ta.style.height = "auto";
    ta.style.height = `${Math.min(ta.scrollHeight, window.innerHeight * 0.4)}px`;
  };

  return (
    <div className="composer-wrap">
      <div className="composer">
        {/* Model Rail — the machined cartridge. Tap to open the model sheet. */}
        <button
          type="button"
          className={`model-rail${streaming ? " live" : ""}`}
          onClick={onOpenModelSheet}
          aria-label="Change model"
        >
          <span className="rail-glyph">{providerGlyph(model?.provider)}</span>
          <span className="rail-main">
            <span className="rail-model-id">{model?.id ?? "select a model"}</span>
            <span className="rail-meta">
              <span>
                {formatTokens(totalTokens)}
                {ctxLimit ? ` / ${formatTokens(ctxLimit)}` : ""}
              </span>
              <span className="ctx-meter" aria-hidden>
                <span className="fill" style={{ width: `${ctxPct}%` }} />
              </span>
              <span className="price-chip">{perMillion(model?.pricing?.completion)}</span>
            </span>
          </span>
          <span className="rail-chevron" aria-hidden>
            <svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="1.5">
              <path d="M4 5.5 7 8.5l3-3" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
          </span>
        </button>

        <div className="composer-box">
          <textarea
            ref={taRef}
            rows={1}
            placeholder={model ? "Message…" : "Pick a model first…"}
            value={text}
            onChange={(e) => {
              setText(e.target.value);
              autoGrow();
            }}
            onKeyDown={onKeyDown}
            aria-label="Message"
          />
          {streaming ? (
            <button className="send-btn stop" onClick={onStop} aria-label="Stop generation">
              <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
                <rect x="4" y="4" width="8" height="8" rx="1.5" />
              </svg>
            </button>
          ) : (
            <button className="send-btn" onClick={send} disabled={!text.trim() || !model} aria-label="Send message">
              <svg width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor" strokeWidth="1.8">
                <path d="M9 15V3M4 8l5-5 5 5" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
            </button>
          )}
        </div>
      </div>
    </div>
  );
}

function isTouchDevice(): boolean {
  return typeof window !== "undefined" && window.matchMedia("(pointer: coarse)").matches;
}
