import { useState, useCallback, useMemo, useEffect } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner';
import { useAppStore } from '@/store/app-store';
import { OpencodeCliStatus, OpencodeCliStatusSkeleton } from '../cli-status/opencode-cli-status';
import { OpencodeModelConfiguration } from './opencode-model-configuration';
import { ProviderToggle } from './provider-toggle';
import { useOpencodeCliStatus, useOpencodeProviders, useOpencodeModels } from '@/hooks/queries';
import { queryKeys } from '@/lib/query-keys';
import type { CliStatus as SharedCliStatus } from '../shared/types';
import type { OpencodeModelId } from '@automaker/types';
import type { OpencodeAuthStatus, OpenCodeProviderInfo } from '../cli-status/opencode-cli-status';

export function OpencodeSettingsTab() {
  const queryClient = useQueryClient();
  const {
    enabledOpencodeModels,
    opencodeDefaultModel,
    setOpencodeDefaultModel,
    toggleOpencodeModel,
    enabledDynamicModelIds,
    toggleDynamicModel,
    setDynamicOpencodeModels,
  } = useAppStore();

  const [isSaving, setIsSaving] = useState(false);

  // React Query hooks for data fetching
  const {
    data: cliStatusData,
    isLoading: isCheckingOpencodeCli,
    refetch: refetchCliStatus,
  } = useOpencodeCliStatus();

  const isCliInstalled = cliStatusData?.installed ?? false;

  const { data: providersData = [], isFetching: isFetchingProviders } = useOpencodeProviders();

  const { data: modelsData = [], isFetching: isFetchingModels } = useOpencodeModels();

  // Sync React Query opencode models data to Zustand store so that the model
  // selector dropdown (PhaseModelSelector) reflects newly enabled models without
  // requiring a page refresh. The selector reads from the Zustand store while
  // this settings tab fetches via React Query — keeping them in sync bridges that gap.
  useEffect(() => {
    if (modelsData.length > 0) {
      setDynamicOpencodeModels(modelsData);
    }
  }, [modelsData, setDynamicOpencodeModels]);

  // Transform CLI status to the expected format
  const cliStatus = useMemo((): SharedCliStatus | null => {
    if (!cliStatusData) return null;
    return {
      success: cliStatusData.success ?? false,
      status: cliStatusData.installed ? 'installed' : 'not_installed',
      method: cliStatusData.auth?.method,
      version: cliStatusData.version,
      path: cliStatusData.path,
      recommendation: cliStatusData.recommendation,
      installCommands: cliStatusData.installCommands,
    };
  }, [cliStatusData]);

  // Transform auth status to the expected format
  const authStatus = useMemo((): OpencodeAuthStatus | null => {
    if (!cliStatusData?.auth) return null;
    // Cast auth to include optional error field for type compatibility
    const auth = cliStatusData.auth as typeof cliStatusData.auth & { error?: string };
    return {
      authenticated: auth.authenticated,
      method: (auth.method as OpencodeAuthStatus['method']) || 'none',
      hasApiKey: auth.hasApiKey,
      hasEnvApiKey: auth.hasEnvApiKey,
      hasOAuthToken: auth.hasOAuthToken,
      error: auth.error,
    };
  }, [cliStatusData]);

  // Refresh all opencode-related queries
  const handleRefreshOpencodeCli = useCallback(async () => {
    await Promise.all([
      queryClient.invalidateQueries({ queryKey: queryKeys.cli.opencode() }),
      queryClient.invalidateQueries({ queryKey: queryKeys.models.opencodeProviders() }),
      queryClient.invalidateQueries({ queryKey: queryKeys.models.opencode() }),
    ]);
    await refetchCliStatus();
    toast.success('OpenCode CLI refreshed');
  }, [queryClient, refetchCliStatus]);

  const handleDefaultModelChange = useCallback(
    (model: OpencodeModelId) => {
      setIsSaving(true);
      try {
        setOpencodeDefaultModel(model);
        toast.success('Default model updated');
      } catch {
        toast.error('Failed to update default model');
      } finally {
        setIsSaving(false);
      }
    },
    [setOpencodeDefaultModel]
  );

  const handleModelToggle = useCallback(
    (model: OpencodeModelId, enabled: boolean) => {
      setIsSaving(true);
      try {
        toggleOpencodeModel(model, enabled);
      } catch {
        toast.error('Failed to update models');
      } finally {
        setIsSaving(false);
      }
    },
    [toggleOpencodeModel]
  );

  const handleDynamicModelToggle = useCallback(
    (modelId: string, enabled: boolean) => {
      setIsSaving(true);
      try {
        toggleDynamicModel(modelId, enabled);
      } catch {
        toast.error('Failed to update dynamic model');
      } finally {
        setIsSaving(false);
      }
    },
    [toggleDynamicModel]
  );

  // Show skeleton only while checking CLI status initially
  if (!cliStatus && isCheckingOpencodeCli) {
    return (
      <div className="space-y-6">
        <OpencodeCliStatusSkeleton />
      </div>
    );
  }

  const isLoadingDynamicModels = isFetchingProviders || isFetchingModels;

  return (
    <div className="space-y-6">
      {/* Provider Visibility Toggle */}
      <ProviderToggle provider="opencode" providerLabel="OpenCode" />

      <OpencodeCliStatus
        status={cliStatus}
        authStatus={authStatus}
        providers={providersData as OpenCodeProviderInfo[]}
        isChecking={isCheckingOpencodeCli}
        onRefresh={handleRefreshOpencodeCli}
      />

      {/* Model Configuration - Only show when CLI is installed */}
      {isCliInstalled && (
        <OpencodeModelConfiguration
          enabledOpencodeModels={enabledOpencodeModels}
          opencodeDefaultModel={opencodeDefaultModel}
          isSaving={isSaving}
          onDefaultModelChange={handleDefaultModelChange}
          onModelToggle={handleModelToggle}
          providers={providersData as OpenCodeProviderInfo[]}
          dynamicModels={modelsData}
          enabledDynamicModelIds={enabledDynamicModelIds}
          onDynamicModelToggle={handleDynamicModelToggle}
          isLoadingDynamicModels={isLoadingDynamicModels}
        />
      )}
    </div>
  );
}

export default OpencodeSettingsTab;
