<!-- [DEF:AssistantChatPanel:Component] -->
<script>
  /**
   * @TIER: CRITICAL
   * @PURPOSE: Slide-out assistant chat panel for natural language command execution and task tracking.
   * @LAYER: UI
   * @RELATION: BINDS_TO -> assistantChatStore
   * @RELATION: CALLS -> frontend.src.lib.api.assistant
   * @RELATION: DISPATCHES -> taskDrawerStore
   * @SEMANTICS: assistant-chat, confirmation, long-running-task, progress-tracking
   * @INVARIANT: User commands and assistant responses are appended in chronological order.
   * @INVARIANT: Risky operations are executed only through explicit confirm action.
   *
   * @UX_STATE: Closed -> Panel is hidden.
   * @UX_STATE: LoadingHistory -> Existing conversation history is loading.
   * @UX_STATE: Idle -> Input is available and no request in progress.
   * @UX_STATE: Sending -> Input locked while request is pending.
   * @UX_STATE: Error -> Failed action rendered as assistant failed message.
   * @UX_FEEDBACK: Started operation surfaces task_id and quick action to open task drawer.
   * @UX_RECOVERY: User can retry command or action from input and action buttons.
   * @UX_TEST: LoadingHistory -> {openPanel: true, expected: loading block visible}
   * @UX_TEST: Sending -> {sendMessage: "branch", expected: send button disabled}
   * @UX_TEST: NeedsConfirmation -> {click: confirm action, expected: started response with task_id}
   */

  import { onMount } from 'svelte';
  import { goto } from '$app/navigation';
  import { t } from '$lib/i18n';
  import Icon from '$lib/ui/Icon.svelte';
  import { openDrawerForTask } from '$lib/stores/taskDrawer.js';
  import {
    assistantChatStore,
    closeAssistantChat,
    setAssistantConversationId,
  } from '$lib/stores/assistantChat.js';
  import {
    sendAssistantMessage,
    confirmAssistantOperation,
    cancelAssistantOperation,
    getAssistantHistory,
  } from '$lib/api/assistant.js';

  let input = '';
  let loading = false;
  let loadingHistory = false;
  let messages = [];
  let initialized = false;

  $: isOpen = $assistantChatStore?.isOpen || false;
  $: conversationId = $assistantChatStore?.conversationId || null;

  // [DEF:loadHistory:Function]
  /**
   * @PURPOSE: Load current conversation history when panel becomes visible.
   * @PRE: Panel is open and history request is not already running.
   * @POST: messages are populated from persisted history and conversation id is synchronized.
   * @SIDE_EFFECT: Performs API call to assistant history endpoint.
   */
  async function loadHistory() {
    if (loadingHistory || !isOpen) return;
    loadingHistory = true;
    try {
      const history = await getAssistantHistory(1, 50, conversationId);
      messages = (history.items || []).map((msg) => ({
        ...msg,
        actions: msg.actions || msg.metadata?.actions || [],
      }));
      if (history.conversation_id && history.conversation_id !== conversationId) {
        setAssistantConversationId(history.conversation_id);
      }
      initialized = true;
      console.log('[AssistantChatPanel][Coherence:OK] History loaded');
    } catch (err) {
      console.error('[AssistantChatPanel][Coherence:Failed] Failed to load history', err);
    } finally {
      loadingHistory = false;
    }
  }
  // [/DEF:loadHistory:Function]

  $: if (isOpen && !initialized) {
    loadHistory();
  }

  // [DEF:appendLocalUserMessage:Function]
  /**
   * @PURPOSE: Add optimistic local user message before backend response.
   * @PRE: text is non-empty command text.
   * @POST: user message appears at the end of messages list.
   */
  function appendLocalUserMessage(text) {
    messages = [
      ...messages,
      {
        message_id: `local-${Date.now()}`,
        role: 'user',
        text,
        created_at: new Date().toISOString(),
      },
    ];
  }
  // [/DEF:appendLocalUserMessage:Function]

  // [DEF:appendAssistantResponse:Function]
  /**
   * @PURPOSE: Normalize and append assistant response payload to chat list.
   * @PRE: response follows assistant message response contract.
   * @POST: assistant message appended with state/task/actions metadata.
   */
  function appendAssistantResponse(response) {
    messages = [
      ...messages,
      {
        message_id: response.response_id,
        role: 'assistant',
        text: response.text,
        state: response.state,
        task_id: response.task_id || null,
        confirmation_id: response.confirmation_id || null,
        actions: response.actions || [],
        created_at: response.created_at,
      },
    ];
  }
  // [/DEF:appendAssistantResponse:Function]

  // [DEF:handleSend:Function]
  /**
   * @PURPOSE: Submit user command to assistant orchestration API.
   * @PRE: input contains a non-empty command and current request is not loading.
   * @POST: assistant response is rendered and conversation id is persisted in store.
   * @SIDE_EFFECT: Triggers backend command execution pipeline.
   */
  async function handleSend() {
    const text = input.trim();
    if (!text || loading) return;

    appendLocalUserMessage(text);
    input = '';
    loading = true;

    try {
      const response = await sendAssistantMessage({
        conversation_id: conversationId,
        message: text,
      });

      if (response.conversation_id) {
        setAssistantConversationId(response.conversation_id);
      }

      appendAssistantResponse(response);
    } catch (err) {
      appendAssistantResponse({
        response_id: `error-${Date.now()}`,
        text: err.message || 'Assistant request failed',
        state: 'failed',
        created_at: new Date().toISOString(),
        actions: [],
      });
    } finally {
      loading = false;
    }
  }
  // [/DEF:handleSend:Function]

  // [DEF:handleAction:Function]
  /**
   * @PURPOSE: Execute assistant action button behavior (open task/reports, confirm, cancel).
   * @PRE: action object is produced by assistant response contract.
   * @POST: UI navigation or follow-up assistant response is appended.
   * @SIDE_EFFECT: May navigate routes or call confirm/cancel API endpoints.
   */
  async function handleAction(action, message) {
    try {
      if (action.type === 'open_task' && action.target) {
        openDrawerForTask(action.target);
        return;
      }

      if (action.type === 'open_reports') {
        goto('/reports');
        return;
      }

      if (action.type === 'confirm' && message.confirmation_id) {
        const response = await confirmAssistantOperation(message.confirmation_id);
        appendAssistantResponse(response);
        return;
      }

      if (action.type === 'cancel' && message.confirmation_id) {
        const response = await cancelAssistantOperation(message.confirmation_id);
        appendAssistantResponse(response);
      }
    } catch (err) {
      appendAssistantResponse({
        response_id: `action-error-${Date.now()}`,
        text: err.message || 'Action failed',
        state: 'failed',
        created_at: new Date().toISOString(),
        actions: [],
      });
    }
  }
  // [/DEF:handleAction:Function]

  // [DEF:handleKeydown:Function]
  /**
   * @PURPOSE: Submit command by Enter while preserving multiline input with Shift+Enter.
   * @PRE: Keyboard event received from chat input.
   * @POST: handleSend is invoked when Enter is pressed without shift modifier.
   */
  function handleKeydown(event) {
    if (event.key === 'Enter' && !event.shiftKey) {
      event.preventDefault();
      handleSend();
    }
  }
  // [/DEF:handleKeydown:Function]

  // [DEF:stateClass:Function]
  /**
   * @PURPOSE: Map assistant state to visual badge style class.
   * @PRE: state is a nullable assistant state string.
   * @POST: Tailwind class string returned for badge rendering.
   */
  function stateClass(state) {
    if (state === 'started') return 'bg-sky-100 text-sky-700 border-sky-200';
    if (state === 'success') return 'bg-emerald-100 text-emerald-700 border-emerald-200';
    if (state === 'needs_confirmation') return 'bg-amber-100 text-amber-700 border-amber-200';
    if (state === 'denied' || state === 'failed') return 'bg-rose-100 text-rose-700 border-rose-200';
    if (state === 'needs_clarification') return 'bg-violet-100 text-violet-700 border-violet-200';
    return 'bg-slate-100 text-slate-700 border-slate-200';
  }
  // [/DEF:stateClass:Function]

  onMount(() => {
    initialized = false;
  });
</script>

{#if isOpen}
  <div class="fixed inset-0 z-[70] bg-slate-900/30" on:click={closeAssistantChat} aria-hidden="true"></div>

  <aside class="fixed right-0 top-0 z-[71] h-full w-full max-w-md border-l border-slate-200 bg-white shadow-2xl">
    <div class="flex h-14 items-center justify-between border-b border-slate-200 px-4">
      <div class="flex items-center gap-2 text-slate-800">
        <Icon name="clipboard" size={18} />
        <h2 class="text-sm font-semibold">{$t.assistant?.title || 'AI Assistant'}</h2>
      </div>
      <button
        class="rounded-md p-1 text-slate-500 transition hover:bg-slate-100 hover:text-slate-900"
        on:click={closeAssistantChat}
        aria-label={$t.assistant?.close || 'Close assistant'}
      >
        <Icon name="close" size={18} />
      </button>
    </div>

    <div class="flex h-[calc(100%-56px)] flex-col">
      <div class="flex-1 space-y-3 overflow-y-auto p-4">
        {#if loadingHistory}
          <div class="rounded-lg border border-slate-200 bg-slate-50 p-3 text-sm text-slate-600">{$t.assistant?.loading_history || 'Loading history...'}</div>
        {:else if messages.length === 0}
          <div class="rounded-lg border border-slate-200 bg-slate-50 p-3 text-sm text-slate-600">
            {$t.assistant?.try_commands || 'Try commands:'}
            <div class="mt-2 space-y-1 text-xs">
              <div>• сделай ветку feature/new-dashboard для дашборда 42</div>
              <div>• запусти миграцию с dev на prod для дашборда 42</div>
              <div>• проверь статус задачи task-123</div>
            </div>
          </div>
        {/if}

        {#each messages as message (message.message_id)}
          <div class={message.role === 'user' ? 'ml-8' : 'mr-8'}>
            <div class="rounded-xl border p-3 {message.role === 'user' ? 'border-sky-200 bg-sky-50' : 'border-slate-200 bg-white'}">
              <div class="mb-1 flex items-center justify-between gap-2">
                <span class="text-[11px] font-semibold uppercase tracking-wide text-slate-500">
                  {message.role === 'user' ? 'You' : 'Assistant'}
                </span>
                {#if message.state}
                  <span class="rounded-md border px-2 py-0.5 text-[10px] font-medium {stateClass(message.state)}">
                    {$t.assistant?.states?.[message.state] || message.state}
                  </span>
                {/if}
              </div>

              <div class="whitespace-pre-wrap text-sm text-slate-800">{message.text}</div>

              {#if message.task_id}
                <div class="mt-2 flex items-center gap-2">
                  <span class="rounded border border-slate-200 bg-slate-50 px-2 py-0.5 text-xs text-slate-700">task_id: {message.task_id}</span>
                  <button
                    class="text-xs font-medium text-sky-700 hover:text-sky-900"
                    on:click={() => openDrawerForTask(message.task_id)}
                  >
                    {$t.assistant?.open_task_drawer || 'Open Task Drawer'}
                  </button>
                </div>
              {/if}

              {#if message.actions?.length}
                <div class="mt-3 flex flex-wrap gap-2">
                  {#each message.actions as action}
                    <button
                      class="rounded-md border border-slate-300 px-2.5 py-1 text-xs font-medium text-slate-700 transition hover:bg-slate-100"
                      on:click={() => handleAction(action, message)}
                    >
                      {action.label}
                    </button>
                  {/each}
                </div>
              {/if}
            </div>
          </div>
        {/each}
      </div>

      <div class="border-t border-slate-200 p-3">
        <div class="flex items-end gap-2">
          <textarea
            bind:value={input}
            rows="2"
            placeholder={$t.assistant?.input_placeholder || 'Type a command...'}
            class="min-h-[52px] w-full resize-y rounded-lg border border-slate-300 px-3 py-2 text-sm outline-none transition focus:border-sky-400 focus:ring-2 focus:ring-sky-100"
            on:keydown={handleKeydown}
          ></textarea>
          <button
            class="rounded-lg bg-sky-600 px-3 py-2 text-sm font-medium text-white transition hover:bg-sky-700 disabled:cursor-not-allowed disabled:opacity-60"
            on:click={handleSend}
            disabled={loading || !input.trim()}
          >
            {loading ? '...' : ($t.assistant?.send || 'Send')}
          </button>
        </div>
      </div>
    </div>
  </aside>
{/if}
<!-- [/DEF:AssistantChatPanel:Component] -->
