import { useCallback, useEffect, useState } from 'react';
import { listen, type UnlistenFn } from '@tauri-apps/api/event';
import { Portfolio } from '../types/financial';
import {
  PortfolioAction,
  PortfolioActionDraft,
  PortfolioActionSeed,
  TerminalCommandResponse,
} from '../types/terminal';

export type PortfolioSnapshotStatus = 'idle' | 'loading' | 'partial' | 'ready' | 'error';

export interface PortfolioWorkflowState {
  isPortfolioMode: boolean;
  activePortfolioAction: PortfolioAction | null;
  portfolioSnapshot: Portfolio | null;
  portfolioSnapshotStatus: PortfolioSnapshotStatus;
  portfolioName: string | null;
  draft: PortfolioActionDraft;
  lastPortfolioCommand: string | null;
}

const EMPTY_DRAFT: PortfolioActionDraft = {
  symbol: '',
  quantity: '',
  price: '',
  amount: '',
};

const createDefaultState = (): PortfolioWorkflowState => ({
  isPortfolioMode: false,
  activePortfolioAction: null,
  portfolioSnapshot: null,
  portfolioSnapshotStatus: 'idle',
  portfolioName: null,
  draft: EMPTY_DRAFT,
  lastPortfolioCommand: null,
});

const mergeDraft = (
  draft: PortfolioActionDraft,
  seed?: PortfolioActionSeed,
): PortfolioActionDraft => ({
  symbol: seed?.symbol ?? draft.symbol,
  quantity: seed?.quantity ?? draft.quantity,
  price: seed?.price ?? draft.price,
  amount: seed?.amount ?? draft.amount,
});

const commandToPortfolioAction = (command: string): PortfolioAction | null => {
  const normalized = command.trim().toLowerCase();

  if (normalized === '/portfolio') {
    return 'overview';
  }
  if (normalized === '/portfolio stats') {
    return 'stats';
  }
  if (normalized.startsWith('/portfolio history')) {
    return 'history';
  }
  if (normalized.startsWith('/buy ')) {
    return 'buy';
  }
  if (normalized.startsWith('/sell ')) {
    return 'sell';
  }
  if (normalized.startsWith('/cash deposit')) {
    return 'deposit';
  }
  if (normalized.startsWith('/cash withdraw')) {
    return 'withdraw';
  }

  return null;
};

const derivePortfolioName = (portfolio: Portfolio | null): string | null => {
  if (!portfolio || portfolio.holdings.length === 0) {
    return null;
  }

  // If there's only one holding, use that symbol
  if (portfolio.holdings.length === 1) {
    return portfolio.holdings[0].symbol;
  }

  // For multiple holdings, use "Portfolio: X holdings" or similar
  return `Portfolio (${portfolio.holdings.length})`;
};

export const isPortfolioCommand = (command: string): boolean =>
  commandToPortfolioAction(command) !== null;

export const usePortfolioWorkflow = () => {
  const [workflows, setWorkflows] = useState<Record<string, PortfolioWorkflowState>>({});

  // Set up Tauri event listeners for progressive portfolio loading
  useEffect(() => {
    console.log('[PortfolioWorkflow] Setting up event listeners');
    const unlistenPromises = [
      // Portfolio loading started
      listen('portfolio:loading_started', () => {
        console.log('[PortfolioWorkflow] Received loading_started event');
        // This event indicates loading has started
        // We don't update state here as it's handled by noteCommandStart
      }),

      // Portfolio loaded with cached data (partial)
      listen<Portfolio>('portfolio:loaded', (event) => {
        console.log('[PortfolioWorkflow] Received loaded event with portfolio:', event.payload);
        // Update all active workspaces with partial data
        setWorkflows((current) => {
          const updated = { ...current };
          Object.keys(updated).forEach((workspaceId) => {
            const workflow = updated[workspaceId];
            // Only update if in loading state and in portfolio mode
            if (workflow.isPortfolioMode && workflow.portfolioSnapshotStatus === 'loading') {
              console.log('[PortfolioWorkflow] Updating workspace', workspaceId, 'to partial state');
              updated[workspaceId] = {
                ...workflow,
                portfolioSnapshot: event.payload,
                portfolioSnapshotStatus: 'partial',
              };
            }
          });
          return updated;
        });
      }),

      // Portfolio ready with fresh quotes
      listen<Portfolio>('portfolio:ready', (event) => {
        console.log('[PortfolioWorkflow] Received ready event with portfolio:', event.payload);
        // Update all active workspaces with fresh data
        setWorkflows((current) => {
          const updated = { ...current };
          Object.keys(updated).forEach((workspaceId) => {
            const workflow = updated[workspaceId];
            // Only update if in loading or partial state and in portfolio mode
            if (
              workflow.isPortfolioMode &&
              (workflow.portfolioSnapshotStatus === 'loading' ||
                workflow.portfolioSnapshotStatus === 'partial')
            ) {
              const freshPortfolio = event.payload;
              const portfolioName = derivePortfolioName(freshPortfolio);
              console.log('[PortfolioWorkflow] Updating workspace', workspaceId, 'to ready state');
              updated[workspaceId] = {
                ...workflow,
                portfolioSnapshot: freshPortfolio,
                portfolioSnapshotStatus: 'ready',
                portfolioName,
              };
            }
          });
          return updated;
        });
      }),

      // Portfolio loading error
      listen('portfolio:error', (event) => {
        console.error('[PortfolioWorkflow] Received error event:', event.payload);
        // Update all active workspaces with error state
        setWorkflows((current) => {
          const updated = { ...current };
          Object.keys(updated).forEach((workspaceId) => {
            const workflow = updated[workspaceId];
            if (workflow.isPortfolioMode && workflow.portfolioSnapshotStatus === 'loading') {
              updated[workspaceId] = {
                ...workflow,
                portfolioSnapshotStatus: 'error',
              };
            }
          });
          return updated;
        });
      }),
    ];

    // Cleanup listeners on unmount
    return () => {
      unlistenPromises.forEach((unlistenPromise: Promise<UnlistenFn>) => {
        unlistenPromise.then((unlisten: UnlistenFn) => unlisten());
      });
    };
  }, []);

  const readWorkflow = useCallback(
    (workspaceId: string): PortfolioWorkflowState =>
      workflows[workspaceId] ?? createDefaultState(),
    [workflows],
  );

  const updateWorkflow = useCallback(
    (
      workspaceId: string,
      updater: (current: PortfolioWorkflowState) => PortfolioWorkflowState,
    ) => {
      setWorkflows((current) => {
        const nextCurrent = current[workspaceId] ?? createDefaultState();
        return {
          ...current,
          [workspaceId]: updater(nextCurrent),
        };
      });
    },
    [],
  );

  const noteCommandStart = useCallback(
    (workspaceId: string, command: string) => {
      const action = commandToPortfolioAction(command);
      if (!action) {
        return;
      }

      updateWorkflow(workspaceId, (current) => ({
        ...current,
        isPortfolioMode: true,
        activePortfolioAction: action,
        lastPortfolioCommand: command,
        portfolioSnapshotStatus:
          action === 'overview' ? 'loading' : current.portfolioSnapshotStatus,
      }));
    },
    [updateWorkflow],
  );

  // Reset portfolio status to loading when /portfolio command is triggered
  const resetPortfolioLoading = useCallback(
    (workspaceId: string) => {
      updateWorkflow(workspaceId, (current) => ({
        ...current,
        portfolioSnapshotStatus: 'loading',
      }));
    },
    [updateWorkflow],
  );

  const noteCommandResponse = useCallback(
    (
      workspaceId: string,
      command: string,
      response: TerminalCommandResponse,
    ) => {
      const action = commandToPortfolioAction(command);
      if (!action) {
        return;
      }

      const latestPortfolioSnapshot =
        response.kind === 'panel' && response.panel.type === 'portfolio'
          ? response.panel.data
          : response.kind === 'text'
            ? response.portfolio ?? null
            : null;

      const portfolioName = derivePortfolioName(latestPortfolioSnapshot);

      updateWorkflow(workspaceId, (current) => {
        // For portfolio overview command, let the event system handle the state updates
        // to avoid conflicts with progressive loading
        if (response.kind === 'panel' && response.panel.type === 'portfolio') {
          return {
            ...current,
            isPortfolioMode: true,
            activePortfolioAction: 'overview',
            // Don't update portfolioSnapshot or status - events handle this
            portfolioName,
            lastPortfolioCommand: command,
          };
        }

        const completedTradeAction =
          action === 'buy' ||
          action === 'sell' ||
          action === 'deposit' ||
          action === 'withdraw';

        return {
          ...current,
          isPortfolioMode: true,
          activePortfolioAction: completedTradeAction ? null : action,
          portfolioSnapshot: latestPortfolioSnapshot ?? current.portfolioSnapshot,
          portfolioSnapshotStatus: latestPortfolioSnapshot
            ? 'ready'
            : current.portfolioSnapshotStatus,
          portfolioName: latestPortfolioSnapshot ? portfolioName : current.portfolioName,
          lastPortfolioCommand: command,
        };
      });
    },
    [updateWorkflow],
  );

  const noteCommandError = useCallback(
    (workspaceId: string, command: string) => {
      const action = commandToPortfolioAction(command);
      if (!action) {
        return;
      }

      updateWorkflow(workspaceId, (current) => ({
        ...current,
        isPortfolioMode: true,
        activePortfolioAction: action,
        portfolioSnapshotStatus:
          action === 'overview' ? 'error' : current.portfolioSnapshotStatus,
        lastPortfolioCommand: command,
      }));
    },
    [updateWorkflow],
  );

  const startPortfolioAction = useCallback(
    (workspaceId: string, action: PortfolioAction, seed?: PortfolioActionSeed) => {
      updateWorkflow(workspaceId, (current) => ({
        ...current,
        isPortfolioMode: true,
        activePortfolioAction: action,
        draft: mergeDraft(
          {
            ...EMPTY_DRAFT,
            ...(action === 'buy' || action === 'sell'
              ? { symbol: current.draft.symbol }
              : {}),
          },
          seed,
        ),
      }));
    },
    [updateWorkflow],
  );

  const clearPortfolioAction = useCallback(
    (workspaceId: string) => {
      updateWorkflow(workspaceId, (current) => ({
        ...current,
        activePortfolioAction: null,
        draft: EMPTY_DRAFT,
      }));
    },
    [updateWorkflow],
  );

  const updateDraft = useCallback(
    (workspaceId: string, patch: Partial<PortfolioActionDraft>) => {
      updateWorkflow(workspaceId, (current) => ({
        ...current,
        draft: {
          ...current.draft,
          ...patch,
        },
      }));
    },
    [updateWorkflow],
  );

  const exitPortfolioMode = useCallback(
    (workspaceId: string) => {
      updateWorkflow(workspaceId, (current) => ({
        ...current,
        isPortfolioMode: false,
        activePortfolioAction: null,
        draft: EMPTY_DRAFT,
      }));
    },
    [updateWorkflow],
  );

  return {
    readWorkflow,
    noteCommandStart,
    noteCommandResponse,
    noteCommandError,
    startPortfolioAction,
    clearPortfolioAction,
    updateDraft,
    exitPortfolioMode,
    resetPortfolioLoading,
  };
};
