import { useState } from "react";
import type { Conversation, SavedResponse } from "../types";
import { PROFESSIONS, SUPPORTED_LANGUAGES } from "../types";
import { exportAllSavedResponses } from "../lib/export";

// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------

/** Truncate saved-response question text to ~80 chars (within ±5 tolerance). */
const QUESTION_TRUNCATE_LENGTH = 80;

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

/**
 * Truncates a question string to approximately 80 characters for sidebar
 * display. When the original exceeds 80 characters the result is truncated
 * at the nearest word boundary within [75, 85] chars and an ellipsis appended.
 *
 * Property 5: displayed length is within [75, 85] when original > 80 chars.
 * Requirements: 8.3
 */
export function truncateQuestion(text: string): string {
  if (text.length <= QUESTION_TRUNCATE_LENGTH) return text;

  // Slice at exactly 80 chars then walk back to the last space within ±5.
  let cutPoint = QUESTION_TRUNCATE_LENGTH;
  const spaceIndex = text.lastIndexOf(" ", QUESTION_TRUNCATE_LENGTH);
  if (spaceIndex >= 75) {
    cutPoint = spaceIndex;
  }

  return text.slice(0, cutPoint).trimEnd() + "…";
}

// ---------------------------------------------------------------------------
// Sub-components
// ---------------------------------------------------------------------------

interface CollapsibleSectionProps {
  title: string;
  defaultOpen?: boolean;
  children: React.ReactNode;
}

function CollapsibleSection({
  title,
  defaultOpen = true,
  children,
}: CollapsibleSectionProps) {
  const [isOpen, setIsOpen] = useState(defaultOpen);

  return (
    <div className="flex flex-col gap-1">
      <button
        type="button"
        onClick={() => setIsOpen((prev) => !prev)}
        className="flex items-center justify-between w-full px-3 py-2 rounded-lg
                   text-xs font-semibold uppercase tracking-widest
                   transition-colors duration-150 hover:bg-white/5"
        style={{ color: "rgba(235,237,247,0.5)" }}
        aria-expanded={isOpen}
      >
        <span>{title}</span>
        <svg
          className="w-3 h-3 transition-transform duration-200"
          style={{ transform: isOpen ? "rotate(0deg)" : "rotate(-90deg)" }}
          viewBox="0 0 12 12"
          fill="none"
          aria-hidden="true"
        >
          <path
            d="M2 4l4 4 4-4"
            stroke="currentColor"
            strokeWidth="1.5"
            strokeLinecap="round"
            strokeLinejoin="round"
          />
        </svg>
      </button>

      {isOpen && (
        <div className="flex flex-col gap-0.5 mt-0.5">{children}</div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Sidebar props
// ---------------------------------------------------------------------------

export interface SidebarProps {
  /** Conversations ordered by last_active_at desc (caller is responsible for ordering). */
  conversations: Conversation[];
  /** Saved responses ordered by saved_at desc (caller is responsible for ordering). */
  savedResponses: SavedResponse[];

  /** Clears the active ChatState and mints a new UUID. */
  onNewConversation: () => void;
  /** Restores a past conversation into the active ChatState. */
  onSelectConversation: (id: string) => void;
  /** Removes a conversation from localStorage. */
  onDeleteConversation: (id: string) => void;

  /** Forks a saved response into a new ChatState. */
  onSelectSavedResponse: (id: string) => void;
  /** Removes a saved response from localStorage. */
  onDeleteSavedResponse: (id: string) => void;

  /** Currently selected profession (empty string = none). */
  profession: string;
  onProfessionChange: (profession: string) => void;

  /** Currently selected language code. */
  language: string;
  onLanguageChange: (language: string) => void;

  /**
   * True when the current Chat_Session has at least one completed Q&A pair.
   * Used to decide whether to show the profession-change notice.
   */
  hasMessages: boolean;

  /**
   * Called when the user clicks the one-click re-run option in the
   * profession-change notice.
   */
  onRerunWithProfession: () => void;
}

// ---------------------------------------------------------------------------
// Sidebar component
// ---------------------------------------------------------------------------

/**
 * Dark sidebar containing:
 * - "New conversation" button
 * - "Download saved responses" button
 * - Profession selector
 * - Language selector
 * - Profession-change notice (when profession changes after ≥1 Q&A pair)
 * - Collapsible "Past conversations" section
 * - Collapsible "Saved responses" section
 *
 * Requirements: 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 9.1, 9.2, 9.3, 9.4, 9.5
 */
export function Sidebar({
  conversations,
  savedResponses,
  onNewConversation,
  onSelectConversation,
  onDeleteConversation,
  onSelectSavedResponse,
  onDeleteSavedResponse,
  profession,
  onProfessionChange,
  language,
  onLanguageChange,
  hasMessages,
  onRerunWithProfession,
}: SidebarProps) {
  /**
   * Track the profession that was active when the last Q&A pair completed.
   * When `profession` diverges from this value and `hasMessages` is true,
   * we show the profession-change notice.
   */
  const [committedProfession, setCommittedProfession] = useState(profession);
  const [showProfessionNotice, setShowProfessionNotice] = useState(false);

  function handleProfessionChange(newProfession: string) {
    onProfessionChange(newProfession);

    if (hasMessages && newProfession !== committedProfession) {
      setShowProfessionNotice(true);
    } else {
      setShowProfessionNotice(false);
    }
  }

  function handleRerun() {
    setCommittedProfession(profession);
    setShowProfessionNotice(false);
    onRerunWithProfession();
  }

  function handleDismissNotice() {
    setCommittedProfession(profession);
    setShowProfessionNotice(false);
  }

  function handleNewConversation() {
    setCommittedProfession(profession);
    setShowProfessionNotice(false);
    onNewConversation();
  }

  return (
    <aside
      className="flex flex-col h-full w-64 shrink-0 overflow-y-auto"
      style={{
        background:
          "linear-gradient(180deg, rgba(84,47,232,0.18) 0%, rgba(11,11,12,1) 55%)",
        borderRight: "1px solid rgba(255,255,255,0.05)",
        color: "#EBEDF7",
      }}
    >
      {/* ------------------------------------------------------------------ */}
      {/* Top action buttons                                                  */}
      {/* ------------------------------------------------------------------ */}

      {/* ------------------------------------------------------------------ */}
      {/* Divider                                                             */}
      {/* ------------------------------------------------------------------ */}
      <div
        className="mx-4 mb-3"
        style={{ borderTop: "1px solid rgba(255,255,255,0.07)" }}
      />

      {/* ------------------------------------------------------------------ */}
      {/* Selectors                                                           */}
      {/* ------------------------------------------------------------------ */}
      <div className="flex flex-col gap-3 px-4 pb-3">
        {/* Profession selector — Requirement 9.1 */}
        <div className="flex flex-col gap-1.5">
          <label
            htmlFor="sidebar-profession"
            className="text-xs font-semibold uppercase tracking-widest"
            style={{ color: "rgba(235,237,247,0.5)" }}
          >
            Profession
          </label>
          <select
            id="sidebar-profession"
            value={profession}
            onChange={(e) => handleProfessionChange(e.target.value)}
            className="w-full rounded-lg px-3 py-2 text-sm outline-none
                       transition-colors duration-150
                       focus:ring-2 focus:ring-white/20"
            style={{
              background: "rgba(255,255,255,0.07)",
              border: "1px solid rgba(255,255,255,0.12)",
              color: "#EBEDF7",
            }}
          >
            <option value="">-- please select --</option>
            {PROFESSIONS.map((p) => (
              <option key={p} value={p}>
                {p}
              </option>
            ))}
          </select>
        </div>

        {/* Language selector — Requirement 9.3 */}
        <div className="flex flex-col gap-1.5">
          <label
            htmlFor="sidebar-language"
            className="text-xs font-semibold uppercase tracking-widest"
            style={{ color: "rgba(235,237,247,0.5)" }}
          >
            Language
          </label>
          <select
            id="sidebar-language"
            value={language}
            onChange={(e) => onLanguageChange(e.target.value)}
            className="w-full rounded-lg px-3 py-2 text-sm outline-none
                       transition-colors duration-150
                       focus:ring-2 focus:ring-white/20"
            style={{
              background: "rgba(255,255,255,0.07)",
              border: "1px solid rgba(255,255,255,0.12)",
              color: "#EBEDF7",
            }}
          >
            {Object.entries(SUPPORTED_LANGUAGES).map(([code, label]) => (
              <option key={code} value={code}>
                {label}
              </option>
            ))}
          </select>
        </div>
      </div>

      {/* ------------------------------------------------------------------ */}
      {/* Profession-change notice — Requirement 9.5                         */}
      {/* ------------------------------------------------------------------ */}
      {showProfessionNotice && (
        <div
          className="mx-4 mb-3 rounded-lg p-3 text-xs flex flex-col gap-2"
          role="status"
          style={{
            background: "rgba(84,47,232,0.25)",
            border: "1px solid rgba(84,47,232,0.5)",
            color: "#EBEDF7",
          }}
        >
          <p>
            The current answer was generated without the{" "}
            <strong>{profession}</strong> profession context. Re-run to get a
            profession-specific response.
          </p>
          <div className="flex gap-2">
            <button
              type="button"
              onClick={handleRerun}
              className="flex-1 rounded-md py-1.5 text-xs font-semibold
                         transition-colors duration-150 hover:opacity-90"
              style={{
                background: "linear-gradient(135deg, #542FE8 0%, #1E3798 100%)",
                color: "#FFFFFF",
              }}
            >
              Re-run with {profession}
            </button>
            <button
              type="button"
              onClick={handleDismissNotice}
              className="rounded-md px-2 py-1.5 text-xs transition-colors
                         duration-150 hover:bg-white/10"
              style={{ color: "rgba(235,237,247,0.6)" }}
              aria-label="Dismiss notice"
            >
              ✕
            </button>
          </div>
        </div>
      )}

      {/* ------------------------------------------------------------------ */}
      {/* Divider                                                             */}
      {/* ------------------------------------------------------------------ */}
      <div
        className="mx-4 mb-3"
        style={{ borderTop: "1px solid rgba(255,255,255,0.07)" }}
      />

      {/* ------------------------------------------------------------------ */}
      {/* Bottom block — new conversation + saved responses + past conversations */}
      {/* ------------------------------------------------------------------ */}
      <div className="flex flex-col gap-2 px-2 pb-4 mt-auto">
        {/* New conversation */}
        <button
          type="button"
          onClick={handleNewConversation}
          className="flex items-center gap-2 w-full rounded-lg px-3 py-2.5
                     text-sm font-medium transition-colors duration-150
                     hover:bg-white/10 active:bg-white/15"
          style={{ color: "#EBEDF7" }}
        >
          <svg className="w-4 h-4 shrink-0" viewBox="0 0 16 16" fill="none" aria-hidden="true">
            <path d="M8 3v10M3 8h10" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
          </svg>
          New conversation
        </button>

        <div style={{ borderTop: "1px solid rgba(255,255,255,0.07)" }} className="my-1" />

        {/* Saved responses */}
        <CollapsibleSection title="Saved responses" defaultOpen={true}>
          {savedResponses.length === 0 ? (
            <p className="px-3 py-2 text-xs" style={{ color: "rgba(235,237,247,0.35)" }}>
              No saved responses yet.
            </p>
          ) : (
            savedResponses.map((sr) => (
              <SavedResponseRow
                key={sr.id}
                savedResponse={sr}
                onSelect={onSelectSavedResponse}
                onDelete={onDeleteSavedResponse}
              />
            ))
          )}
        </CollapsibleSection>

        <button
          type="button"
          onClick={() => exportAllSavedResponses(savedResponses)}
          disabled={savedResponses.length === 0}
          className="flex items-center gap-2 w-full rounded-lg px-3 py-2
                     text-sm font-medium transition-colors duration-150
                     hover:bg-white/10 active:bg-white/15
                     disabled:opacity-40 disabled:cursor-not-allowed"
          style={{ color: "#EBEDF7" }}
          title={savedResponses.length === 0 ? "No saved responses to download" : "Download all saved responses as Markdown"}
        >
          <svg className="w-4 h-4 shrink-0" viewBox="0 0 16 16" fill="none" aria-hidden="true">
            <path d="M8 2v8M5 7l3 3 3-3M3 12h10" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
          </svg>
          Download saved responses
        </button>

        {/* Divider between saved responses and past conversations */}
        <div style={{ borderTop: "1px solid rgba(255,255,255,0.07)" }} className="my-1" />

        {/* Past conversations */}
        <CollapsibleSection title="Past conversations" defaultOpen={true}>
          {conversations.length === 0 ? (
            <p className="px-3 py-2 text-xs" style={{ color: "rgba(235,237,247,0.35)" }}>
              No conversations yet.
            </p>
          ) : (
            conversations.map((conv) => (
              <ConversationRow
                key={conv.id}
                conversation={conv}
                onSelect={onSelectConversation}
                onDelete={onDeleteConversation}
              />
            ))
          )}
        </CollapsibleSection>
      </div>
    </aside>
  );
}

// ---------------------------------------------------------------------------
// ConversationRow
// ---------------------------------------------------------------------------

interface ConversationRowProps {
  conversation: Conversation;
  onSelect: (id: string) => void;
  onDelete: (id: string) => void;
}

function ConversationRow({
  conversation,
  onSelect,
  onDelete,
}: ConversationRowProps) {
  const fullQuestion =
    conversation.messages.find((m) => m.role === "user")?.content ||
    conversation.title;

  return (
    <div
      className="group flex items-start gap-1 rounded-lg px-2 py-1.5
                 transition-colors duration-150 hover:bg-white/8"
    >
      <button
        type="button"
        onClick={() => onSelect(conversation.id)}
        className="flex-1 text-left text-sm leading-snug break-words transition-colors duration-150"
        style={{ color: "#EBEDF7" }}
      >
        {fullQuestion}
      </button>
      <button
        type="button"
        onClick={(e) => {
          e.stopPropagation();
          onDelete(conversation.id);
        }}
        className="shrink-0 rounded p-1 opacity-0 group-hover:opacity-100
                   transition-opacity duration-150 hover:bg-white/10"
        style={{ color: "rgba(235,237,247,0.5)" }}
        aria-label={`Delete conversation: ${conversation.title}`}
        title="Delete conversation"
      >
        <svg
          className="w-3.5 h-3.5"
          viewBox="0 0 14 14"
          fill="none"
          aria-hidden="true"
        >
          <path
            d="M2 2l10 10M12 2L2 12"
            stroke="currentColor"
            strokeWidth="1.5"
            strokeLinecap="round"
          />
        </svg>
      </button>
    </div>
  );
}

// ---------------------------------------------------------------------------
// SavedResponseRow
// ---------------------------------------------------------------------------

interface SavedResponseRowProps {
  savedResponse: SavedResponse;
  onSelect: (id: string) => void;
  onDelete: (id: string) => void;
}

function SavedResponseRow({
  savedResponse,
  onSelect,
  onDelete,
}: SavedResponseRowProps) {
  return (
    <div
      className="group flex items-start gap-1 rounded-lg px-2 py-1.5
                 transition-colors duration-150 hover:bg-white/8"
    >
      <button
        type="button"
        onClick={() => onSelect(savedResponse.id)}
        className="flex-1 text-left text-sm leading-snug break-words transition-colors duration-150"
        style={{ color: "#EBEDF7" }}
      >
        {savedResponse.question}
      </button>
      <button
        type="button"
        onClick={(e) => {
          e.stopPropagation();
          onDelete(savedResponse.id);
        }}
        className="shrink-0 rounded p-1 mt-0.5 opacity-0 group-hover:opacity-100
                   transition-opacity duration-150 hover:bg-white/10"
        style={{ color: "rgba(235,237,247,0.5)" }}
        aria-label={`Delete saved response: ${savedResponse.question}`}
        title="Delete saved response"
      >
        <svg
          className="w-3.5 h-3.5"
          viewBox="0 0 14 14"
          fill="none"
          aria-hidden="true"
        >
          <path
            d="M2 2l10 10M12 2L2 12"
            stroke="currentColor"
            strokeWidth="1.5"
            strokeLinecap="round"
          />
        </svg>
      </button>
    </div>
  );
}
