// Copyright (c) 2026 PowerOn AG
// All rights reserved.
/**
 * WorkspacePage -- Unified AI Workspace (Prompt-Centric Canvas)
 *
 * Desktop:
 *   Top bar:  Kontext (links) · aktiver Chat + Auswahl + Neuer Chat (rechts)
 *   Stage:    optional links gedocktes Kontext-Panel (Daten/Aktivität/Vorschau)
 *             + zentrale Chat-Spalte (ChatStream + WorkspaceInput)
 * Mobile:     Top bar (Chat + Kontext) · Chat stage · fixed prompt · Bottom-Sheets
 */

import React, { useState, useCallback, useRef, useEffect } from 'react';
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
import { useCurrentInstance } from '../../../hooks/useCurrentInstance';
import { useFileOperations } from '../../../hooks/useFiles';
import { useWorkspace } from './useWorkspace';
import { ChatStream } from './ChatStream';
import { WorkspaceInput } from './WorkspaceInput';
import type { WorkspaceInputHandle, TreeItemDrop } from './WorkspaceInput';
import { ChatsTab } from '../../../components/UnifiedDataBar';
import type { UdbContext, AddToChat_FileItem, AddToChat_FeatureSource } from '../../../components/UnifiedDataBar';
import { FaFolderOpen, FaPlus } from 'react-icons/fa';
import api from '../../../api';
import { _defaultProviderSelection, _toBackendProviders } from '../../../components/ProviderSelector';
import type { ProviderSelection } from '../../../components/ProviderSelector';
import { useBilling } from '../../../hooks/useBilling';
import { useLanguage } from '../../../providers/language/LanguageContext';
import { StackLayout } from '../../../components/Layout/StackLayout';
import { PanelLayout } from '../../../components/Layout/PanelLayout';
import { FloatingPortal } from '../../../components/UiComponents/FloatingPortal';
import { WorkspaceContextSidebar, type WorkspaceCtxTab } from './WorkspaceContextSidebar';
import styles from './WorkspacePage.module.css';

interface WorkspacePageProps {
  persistentInstanceId?: string;
  persistentMandateId?: string;
}

export const WorkspacePage: React.FC<WorkspacePageProps> = ({ persistentInstanceId, persistentMandateId }) => {
  const { t } = useLanguage();
  const { instance } = useCurrentInstance();
  const instanceId = persistentInstanceId || instance?.id || '';
  const workspace = useWorkspace(instanceId);
  const fileOps = useFileOperations();
  const navigate = useNavigate();
  const { mandateId: routeMandateId, featureCode, instanceId: routeInstanceId } = useParams<{
    mandateId: string; featureCode: string; instanceId: string;
  }>();
  const mandateId = persistentMandateId || routeMandateId;
  const [searchParams, setSearchParams] = useSearchParams();
  const [udbTab, setUdbTab] = useState<WorkspaceCtxTab>(() => {
    const tab = new URLSearchParams(window.location.search).get('ctxTab');
    if (tab === 'files' || tab === 'sources' || tab === 'activity' || tab === 'preview') return tab;
    if (tab === 'data') return 'files';
    return 'files';
  });
  const [activeChatLabel, setActiveChatLabel] = useState('');
  const [chatPickerOpen, setChatPickerOpen] = useState(false);
  const [ctxPanelOpen, setCtxPanelOpen] = useState(() => {
    try {
      return localStorage.getItem(`workspace-ctx-open-${instanceId}`) === '1';
    } catch {
      return false;
    }
  });
  const [selectedFileId, setSelectedFileId] = useState<string | null>(null);
  const workspaceInputRef = useRef<WorkspaceInputHandle>(null);
  const [providerSelection, setProviderSelection] = useState<ProviderSelection>(_defaultProviderSelection());
  const { allowedProviders } = useBilling();
  const [isDragOver, setIsDragOver] = useState(false);
  const [draftAppend, setDraftAppend] = useState('');
  const dragCounterRef = useRef(0);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const autoStartHandled = useRef(false);
  const [isMobile, setIsMobile] = useState<boolean>(() =>
    typeof window !== 'undefined' ? window.innerWidth <= 1024 : false,
  );
  const [ctxSidebarCollapsed, setCtxSidebarCollapsed] = useState(false);
  const [mobileChatSheetOpen, setMobileChatSheetOpen] = useState(false);
  const [mobileCtxSheetOpen, setMobileCtxSheetOpen] = useState(false);
  const [mobileCtxSheetExpanded, setMobileCtxSheetExpanded] = useState(false);
  const [chatListRefreshKey, setChatListRefreshKey] = useState(0);
  const chatPickerBtnRef = useRef<HTMLButtonElement>(null);

  useEffect(() => {
    if (!instanceId) return;
    try {
      setCtxPanelOpen(localStorage.getItem(`workspace-ctx-open-${instanceId}`) === '1');
    } catch { /* noop */ }
  }, [instanceId]);

  const _toggleCtxPanel = useCallback(() => {
    setCtxPanelOpen((prev) => {
      const next = !prev;
      if (next) {
        setCtxSidebarCollapsed(false);
      }
      try {
        localStorage.setItem(`workspace-ctx-open-${instanceId}`, next ? '1' : '0');
      } catch { /* noop */ }
      return next;
    });
  }, [instanceId]);

  const _setCtxTab = useCallback((tab: WorkspaceCtxTab) => {
    setUdbTab(tab);
    setSearchParams((prev) => {
      const next = new URLSearchParams(prev);
      next.set('ctxTab', tab);
      return next;
    }, { replace: true });
  }, [setSearchParams]);

  useEffect(() => {
    const _handleResize = () => {
      setIsMobile(window.innerWidth <= 1024);
    };
    _handleResize();
    window.addEventListener('resize', _handleResize);
    return () => window.removeEventListener('resize', _handleResize);
  }, []);

  useEffect(() => {
    if (!isMobile) {
      setMobileChatSheetOpen(false);
      setMobileCtxSheetOpen(false);
      setMobileCtxSheetExpanded(false);
    }
  }, [isMobile]);

  useEffect(() => {
    if (autoStartHandled.current || !instanceId || workspace.isProcessing) return;
    const prompt = searchParams.get('prompt');
    const autoStart = searchParams.get('autoStart') === 'true';
    if (prompt) {
      autoStartHandled.current = true;
      setSearchParams({}, { replace: true });
      if (autoStart) {
        const resolvedProviders = _toBackendProviders(providerSelection, allowedProviders);
        workspace.sendMessage(prompt, [], [], resolvedProviders, []);
      } else {
        setDraftAppend(prompt);
      }
    }
  }, [instanceId, searchParams, setSearchParams, workspace, providerSelection, allowedProviders]);

  const _resolveTreeItemsToFileIds = useCallback(async (items: TreeItemDrop[]) => {
    const out: string[] = [];
    for (const it of items) {
      if (it.type !== 'group') {
        out.push(it.id);
      }
    }
    return [...new Set(out)];
  }, []);

  const _uploadAndAttach = useCallback(async (file: File) => {
    const result = await fileOps.handleFileUpload(file, undefined, instanceId);
    if (result.success && result.fileData) {
      const data = result.fileData.file || result.fileData;
      if (data?.id) {
        workspaceInputRef.current?.attachFileIds([data.id]);
      }
      workspace.refreshFiles();
    }
  }, [fileOps, workspace, instanceId]);

  const _consumeDataTransferFilesOrChat = useCallback(async (dt: React.DragEvent['dataTransfer']) => {
    const chatId = dt.getData('application/chat-id');
    if (chatId) {
      try {
        const res = await api.post(`/api/workspace/${instanceId}/resolve-rag`, { chatId });
        const body = res.data ?? {};
        if (body.summary) setDraftAppend(body.summary);
      } catch (err) {
        console.error('RAG resolve failed for dropped chat:', err);
      }
      return true;
    }
    if (workspaceInputRef.current && (await workspaceInputRef.current.ingestTreeDataTransfer(dt))) {
      return true;
    }
    if (dt.files && dt.files.length > 0) {
      for (const file of Array.from(dt.files)) {
        await _uploadAndAttach(file);
      }
      return true;
    }
    return false;
  }, [_uploadAndAttach, instanceId]);

  const _isCenterDropInteresting = useCallback((e: React.DragEvent) => {
    const types = e.dataTransfer.types;
    return (
      types.includes('application/tree-items') ||
      types.includes('application/group-file-ids') ||
      types.includes('application/group-id') ||
      types.includes('application/porta-group') ||
      types.includes('application/file-id') ||
      types.includes('application/file-ids') ||
      types.includes('application/chat-id') ||
      types.includes('Files')
    );
  }, []);

  const _handleDragEnter = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    dragCounterRef.current++;
    if (_isCenterDropInteresting(e)) setIsDragOver(true);
  }, [_isCenterDropInteresting]);

  const _handleDragLeave = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    dragCounterRef.current--;
    if (dragCounterRef.current === 0) setIsDragOver(false);
  }, []);

  const _handleDragOver = useCallback((e: React.DragEvent) => {
    if (!_isCenterDropInteresting(e)) return;
    e.preventDefault();
    e.stopPropagation();
    e.dataTransfer.dropEffect = 'copy';
  }, [_isCenterDropInteresting]);

  const _handleDrop = useCallback(async (e: React.DragEvent) => {
    const alreadyHandled = e.defaultPrevented;
    e.preventDefault();
    e.stopPropagation();
    dragCounterRef.current = 0;
    setIsDragOver(false);

    if (!alreadyHandled) {
      await _consumeDataTransferFilesOrChat(e.dataTransfer);
    }
  }, [_consumeDataTransferFilesOrChat]);

  const _handleFileInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    if (e.target.files && e.target.files.length > 0) {
      Array.from(e.target.files).forEach(file => _uploadAndAttach(file));
      e.target.value = '';
    }
  }, [_uploadAndAttach]);

  const _handleSendToChat_Files = useCallback((items: AddToChat_FileItem[]) => {
    void workspaceInputRef.current?.attachTreeItems(
      items.map(i => ({ id: i.id, type: i.type, name: i.name })),
    );
  }, []);

  if (!instanceId) {
    return (
      <div style={{ padding: 32, textAlign: 'center', color: '#999' }}>
        {t('Keine Workspace-Instanz ausgewählt.')}
      </div>
    );
  }

  const _handleFileSelect = (fileId: string) => {
    setSelectedFileId(fileId);
    if (isMobile) {
      setSearchParams((prev) => {
        const next = new URLSearchParams(prev);
        next.set('ctxTab', 'preview');
        return next;
      }, { replace: true });
      setUdbTab('preview');
      setMobileCtxSheetOpen(true);
    } else {
      setCtxSidebarCollapsed(false);
      setCtxPanelOpen(true);
      setUdbTab('preview');
      setSearchParams((prev) => {
        const next = new URLSearchParams(prev);
        next.set('ctxTab', 'preview');
        return next;
      }, { replace: true });
    }
  };

  const _handleConversationSelect = useCallback((wfId: string, _featureInstanceId?: string, label?: string) => {
    workspace.loadWorkflow(wfId);
    if (label) setActiveChatLabel(label);
    setChatPickerOpen(false);
    setMobileChatSheetOpen(false);
  }, [workspace]);

  const _handleCreateNewChat = useCallback(() => {
    workspace.resetToNew();
    setActiveChatLabel('');
    setChatPickerOpen(false);
    setMobileChatSheetOpen(false);
    setChatListRefreshKey(k => k + 1);
  }, [workspace]);

  const _handleRenameChat = useCallback(async (chatId: string, newName: string) => {
    try {
      await api.patch(`/api/workspace/${instanceId}/workflows/${chatId}`, { name: newName });
    } catch (err) {
      console.error('Failed to rename chat:', err);
    }
  }, [instanceId]);

  const _handleDeleteChat = useCallback(async (chatId: string) => {
    try {
      await api.delete(`/api/workspace/${instanceId}/workflows/${chatId}`);
      if (workspace.workflowId === chatId) {
        workspace.resetToNew();
      }
    } catch (err) {
      console.error('Failed to delete chat:', err);
    }
  }, [instanceId, workspace]);

  const _udbContext: UdbContext = {
    instanceId: instanceId,
    mandateId: mandateId,
    featureInstanceId: instanceId,
  };

  const _handleSourcesChanged = useCallback(() => {
    workspace.refreshDataSources();
    workspace.refreshFeatureDataSources();
  }, [workspace]);

  const [pendingAttachFdsId, setPendingAttachFdsId] = useState<string>('');

  const _handleSendToChat_FeatureSource = useCallback(async (params: AddToChat_FeatureSource) => {
    try {
      const res = await api.post(`/api/workspace/${instanceId}/feature-datasources`, {
        featureInstanceId: params.featureInstanceId,
        featureCode: params.featureCode,
        tableName: params.tableName || '',
        objectKey: params.objectKey,
        label: params.label,
      });
      const newId =
        res.data?.id ||
        res.data?.featureDataSource?.id ||
        res.data?.dataSource?.id ||
        '';
      if (newId) {
        await workspace.refreshFeatureDataSources();
        setPendingAttachFdsId(newId);
      }
    } catch (err) {
      console.error('Failed to add feature source to chat:', err);
    }
  }, [instanceId, workspace]);

  const [pendingAttachDsId, setPendingAttachDsId] = useState<string>('');
  const [pendingAttachDsLabel, setPendingAttachDsLabel] = useState<string>('');
  const _handleAttachDataSource = useCallback(async (dsId: string) => {
    await workspace.refreshDataSources();
    setPendingAttachDsId(dsId);
  }, [workspace]);

  const _handleDataSourceDrop = useCallback(async (params: { connectionId: string; sourceType: string; path: string; label: string; displayPath?: string }) => {
    try {
      const res = await api.post(`/api/workspace/${instanceId}/datasources`, {
        connectionId: params.connectionId,
        sourceType: params.sourceType,
        path: params.path,
        label: params.label,
        displayPath: params.displayPath || params.label,
      });
      const newId = res.data?.id || res.data?.dataSource?.id;
      if (newId) {
        setPendingAttachDsLabel(params.label || params.displayPath || '');
        await workspace.refreshDataSources();
        setPendingAttachDsId(newId);
      }
    } catch (err) {
      console.error('Failed to drop data source to chat:', err);
    }
  }, [instanceId, workspace]);

  const _contextSidebar = (allowCollapse = true, fillWidth = false) => (
    <WorkspaceContextSidebar
      context={_udbContext}
      activeTab={udbTab}
      onTabChange={_setCtxTab}
      collapsed={ctxSidebarCollapsed}
      onToggleCollapsed={() => setCtxSidebarCollapsed(v => !v)}
      allowCollapse={allowCollapse}
      fillWidth={fillWidth}
      onFileSelect={_handleFileSelect}
      onSourcesChanged={_handleSourcesChanged}
      onSendToChat_Files={_handleSendToChat_Files}
      onSendToChat_FeatureSource={_handleSendToChat_FeatureSource}
      onAttachDataSource={_handleAttachDataSource}
      toolActivities={workspace.toolActivities}
      instanceId={instanceId}
      selectedFileId={selectedFileId}
      files={workspace.files}
    />
  );

  const _displayChatLabel = activeChatLabel || '...';

  const _desktopTopBar = (
    <div className={styles.topBar}>
      <button
        type="button"
        className={`${styles.ctxToggle} ${ctxPanelOpen ? styles.ctxToggleActive : ''}`}
        onClick={_toggleCtxPanel}
        title={t('Kontext')}
        aria-pressed={ctxPanelOpen}
      >
        <FaFolderOpen aria-hidden />
      </button>
      <span className={styles.topBarGrow} />
      <span className={styles.chatName} title={_displayChatLabel}>{_displayChatLabel}</span>
      <div className={styles.chatPickerWrap}>
        <button
          ref={chatPickerBtnRef}
          type="button"
          className={`${styles.iconBtn} ${chatPickerOpen ? styles.iconBtnActive : ''}`}
          onClick={() => setChatPickerOpen(v => !v)}
          title={t('Chat auswählen')}
          aria-expanded={chatPickerOpen}
        >
          <FaFolderOpen aria-hidden />
        </button>
        <FloatingPortal
          open={chatPickerOpen}
          anchorRef={chatPickerBtnRef}
          onClose={() => setChatPickerOpen(false)}
          placement="bottom"
          align="end"
          keepMounted
        >
          <div className={styles.chatPickerDrop}>
            <div className={styles.chatPickerHead}>
              <span>{t('Chats')}</span>
              <button type="button" className={styles.newChatBtn} onClick={_handleCreateNewChat} title={t('Neuer Chat')}>
                <FaPlus aria-hidden />
              </button>
            </div>
            <ChatsTab
              context={_udbContext}
              onSelectChat={_handleConversationSelect}
              activeWorkflowId={workspace.workflowId ?? undefined}
              chatListRefreshKey={chatListRefreshKey}
              onRenameChat={_handleRenameChat}
              onDeleteChat={_handleDeleteChat}
            />
          </div>
        </FloatingPortal>
      </div>
      <button type="button" className={styles.iconBtn} onClick={_handleCreateNewChat} title={t('Neuer Chat')}>
        <FaPlus aria-hidden />
      </button>
    </div>
  );

  const _centerColumn = (
    <div
      className={styles.centerColumn}
      onDragEnter={_handleDragEnter}
      onDragLeave={_handleDragLeave}
      onDragOver={_handleDragOver}
      onDrop={_handleDrop}
    >
      {isDragOver && (
        <div className={styles.dragOverlay}>
          {t('Dateien oder Gruppen hier ablegen')}
        </div>
      )}
      <ChatStream
        messages={workspace.messages}
        agentProgress={workspace.agentProgress}
        isProcessing={workspace.isProcessing}
        pendingEdits={workspace.pendingEdits}
        onAcceptEdit={workspace.acceptEdit}
        onRejectEdit={workspace.rejectEdit}
        onOpenEditor={() => navigate(`/mandates/${mandateId}/${featureCode}/${routeInstanceId}/editor`)}
      />
      <WorkspaceInput
        ref={workspaceInputRef}
        instanceId={instanceId}
        onSend={(prompt, fileIds, dataSourceIds, featureDataSourceIds, options) => {
          const resolvedProviders = _toBackendProviders(providerSelection, allowedProviders);
          workspace.sendMessage(prompt, fileIds || [], dataSourceIds, resolvedProviders, featureDataSourceIds, options);
        }}
        isProcessing={workspace.isProcessing}
        onStop={workspace.stopProcessing}
        files={workspace.files}
        dataSources={workspace.dataSources}
        featureDataSources={workspace.featureDataSources}
        resolveTreeItemsToFileIds={_resolveTreeItemsToFileIds}
        onFileUploadClick={() => fileInputRef.current?.click()}
        uploading={fileOps.uploadingFile}
        providerSelection={providerSelection}
        onProviderSelectionChange={setProviderSelection}
        isMobile={isMobile}
        onFeatureSourceDrop={_handleSendToChat_FeatureSource}
        onDataSourceDrop={_handleDataSourceDrop}
        pendingAttachDsId={pendingAttachDsId}
        pendingAttachDsLabel={pendingAttachDsLabel}
        onPendingAttachDsConsumed={() => { setPendingAttachDsId(''); setPendingAttachDsLabel(''); }}
        pendingAttachFdsId={pendingAttachFdsId}
        onPendingAttachFdsConsumed={() => setPendingAttachFdsId('')}
        draftAppend={draftAppend}
        onDraftAppendConsumed={() => setDraftAppend('')}
        workflowId={workspace.workflowId}
        loadedAttachedDataSourceIds={workspace.loadedAttachedDataSourceIds}
        loadedAttachedFeatureDataSourceIds={workspace.loadedAttachedFeatureDataSourceIds}
        loadedDataSourceLabels={workspace.loadedDataSourceLabels}
        loadedFeatureDataSourceLabels={workspace.loadedFeatureDataSourceLabels}
        loadedNonce={workspace.loadedNonce}
      />
    </div>
  );

  return (
    <StackLayout variant="table">
      <StackLayout.Body className={styles.layoutFill}>
        <input ref={fileInputRef} type="file" multiple style={{ display: 'none' }} onChange={_handleFileInputChange} />

        {isMobile ? (
          <div className={styles.mobileShell}>
            <div className={styles.mobileTopBar}>
              <button
                type="button"
                className={styles.mobileChatPickerBtn}
                onClick={() => setMobileChatSheetOpen(true)}
                title={t('Chat auswählen')}
              >
                <span>{_displayChatLabel}</span>
                <span aria-hidden>▾</span>
              </button>
              <span className={styles.topBarGrow} />
              <button
                type="button"
                className={`${styles.ctxToggle} ${mobileCtxSheetOpen ? styles.ctxToggleActive : ''}`}
                onClick={() => {
                  setCtxSidebarCollapsed(false);
                  setMobileCtxSheetOpen(true);
                }}
                title={t('Kontext')}
              >
                <FaFolderOpen aria-hidden />
              </button>
            </div>
            <div className={styles.mobileStage}>
              {_centerColumn}
            </div>

            {mobileChatSheetOpen && (
              <>
                <div className={styles.mobileSheetOverlay} onClick={() => setMobileChatSheetOpen(false)} />
                <div className={styles.mobileBottomSheet} onClick={e => e.stopPropagation()}>
                  <div className={styles.mobileSheetGrab} />
                  <div className={styles.mobileSheetHead}>
                    <span>{t('Chats')}</span>
                    <span className={styles.mobileSheetHeadGrow} />
                    <button type="button" className={styles.newChatBtn} onClick={_handleCreateNewChat} title={t('Neuer Chat')}>
                      <FaPlus aria-hidden />
                    </button>
                    <button type="button" className={styles.mobileSheetDoneBtn} onClick={() => setMobileChatSheetOpen(false)}>
                      {t('Fertig')}
                    </button>
                  </div>
                  <div className={styles.mobileSheetBody}>
                    <ChatsTab
                      context={_udbContext}
                      onSelectChat={_handleConversationSelect}
                      activeWorkflowId={workspace.workflowId ?? undefined}
                      chatListRefreshKey={chatListRefreshKey}
                      onRenameChat={_handleRenameChat}
                      onDeleteChat={_handleDeleteChat}
                    />
                  </div>
                </div>
              </>
            )}

            {mobileCtxSheetOpen && (
              <>
                <div className={styles.mobileSheetOverlay} onClick={() => { setMobileCtxSheetOpen(false); setMobileCtxSheetExpanded(false); }} />
                <div
                  className={`${styles.mobileBottomSheet} ${mobileCtxSheetExpanded ? styles.mobileBottomSheetFull : styles.mobileBottomSheetTall}`}
                  onClick={e => e.stopPropagation()}
                >
                  <button
                    type="button"
                    className={styles.mobileSheetGrab}
                    aria-label={mobileCtxSheetExpanded ? 'Verkleinern' : 'Vollbild'}
                    onClick={() => setMobileCtxSheetExpanded(v => !v)}
                  />
                  <div className={styles.mobileSheetHead}>
                    <span>{t('Kontext')}</span>
                    <span className={styles.mobileSheetHeadGrow} />
                    <button
                      type="button"
                      className={styles.mobileSheetExpandBtn}
                      onClick={() => setMobileCtxSheetExpanded(v => !v)}
                    >
                      {mobileCtxSheetExpanded ? '↓' : '↑'}
                    </button>
                    <button type="button" className={styles.mobileSheetDoneBtn} onClick={() => { setMobileCtxSheetOpen(false); setMobileCtxSheetExpanded(false); }}>
                      {t('Fertig')}
                    </button>
                  </div>
                  <div className={styles.mobileSheetBody}>
                    {_contextSidebar(false)}
                  </div>
                </div>
              </>
            )}
          </div>
        ) : (
          <div className={styles.workspaceShell}>
            {_desktopTopBar}
            <div className={styles.mainStage}>
              {ctxPanelOpen && !ctxSidebarCollapsed ? (
                <PanelLayout
                  persistenceKey="workspace-main-split"
                  direction="horizontal"
                  panes={[
                    { id: 'context', defaultSize: 26, minSize: 16, maxSize: 50, content: _contextSidebar(true, true) },
                    { id: 'chat', defaultSize: 74, content: _centerColumn },
                  ]}
                />
              ) : (
                <>
                  {ctxPanelOpen && _contextSidebar()}
                  {_centerColumn}
                </>
              )}
            </div>
          </div>
        )}
      </StackLayout.Body>
    </StackLayout>
  );
};

export default WorkspacePage;
