import React, { createContext, useContext, useReducer, type ReactNode } from "react";
import type { 
  AppState,
  QuickFilter,
  UnifiedAppState,
  UnifiedAppAction,
} from "../types/index.ts";
import { filterProjects, sortProjects } from "../utils/project-utils.ts";
import {
  filterByViewMode,
  filterUnifiedRepos,
  filterUnifiedReposByQuickFilter,
  getUnifiedRepoLanguage,
  sortUnifiedRepos,
} from "../github/unified.ts";
import { appReducer, initialState } from "./reducer.ts";

/**
 * Store context
 */
interface StoreContextValue {
  state: UnifiedAppState;
  dispatch: React.Dispatch<UnifiedAppAction>;
}

export const StoreContext = createContext<StoreContextValue | null>(null);

/**
 * Store provider component
 */
export function StoreProvider({ children }: { children: ReactNode }) {
  const [state, dispatch] = useReducer(appReducer, initialState);

  return (
    <StoreContext.Provider value={{ state, dispatch }}>
      {children}
    </StoreContext.Provider>
  );
}

/**
 * Test store provider - accepts initial state and optional mock dispatch
 * Used for testing components without mock.module()
 */
export function TestStoreProvider({
  children,
  initialState: testInitialState,
  dispatch: mockDispatch,
}: {
  children: ReactNode;
  initialState: UnifiedAppState;
  dispatch?: React.Dispatch<UnifiedAppAction>;
}) {
  const [state, realDispatch] = useReducer(appReducer, testInitialState);
  const dispatch = mockDispatch ?? realDispatch;

  return (
    <StoreContext.Provider value={{ state, dispatch }}>
      {children}
    </StoreContext.Provider>
  );
}

/**
 * Hook to access the store
 */
export function useStore(): StoreContextValue {
  const context = useContext(StoreContext);
  if (!context) {
    throw new Error("useStore must be used within a StoreProvider");
  }
  return context;
}

/**
 * Apply quick filter to projects
 */
function applyQuickFilter(projects: AppState["projects"], quickFilter: QuickFilter) {
  if (quickFilter === "all") return projects;

  return projects.filter((p) => {
    switch (quickFilter) {
      case "dirty":
        return p.status?.isDirty;
      case "unpushed":
        return p.status?.isAhead && p.status?.unpushedCommits > 0;
      case "no-remote":
        return p.type === "git" && !p.status?.hasRemote;
      default:
        return true;
    }
  });
}

/**
 * Hook to get filtered and sorted projects
 */
export function useFilteredProjects() {
  const { state } = useStore();
  const { projects, filterText, quickFilter, sortBy, sortDirection } = state;

  let result = projects;

  // Apply quick filter first
  result = applyQuickFilter(result, quickFilter);

  // Apply text filter
  if (filterText) {
    result = filterProjects(result, filterText);
  }

  // Apply sort
  result = sortProjects(result, sortBy, sortDirection);

  return result;
}

/**
 * Hook to get selected projects
 */
export function useSelectedProjects() {
  const { state } = useStore();
  const filteredProjects = useFilteredProjects();
  const { selectedIndices, cursorIndex } = state;

  // If nothing selected, return the project at cursor
  if (selectedIndices.size === 0) {
    const current = filteredProjects[cursorIndex];
    return current ? [current] : [];
  }

  // Return selected projects (filter out undefined and properly type)
  return [...selectedIndices]
    .map((i) => filteredProjects[i])
    .filter((p): p is NonNullable<typeof p> => p !== undefined);
}

/**
 * Hook to get filtered and sorted unified repos
 */
export function useFilteredUnifiedRepos() {
  const { state } = useStore();
  const { unifiedRepos, viewMode, filterText, quickFilter, sortBy, sortDirection, languageFilter } = state;

  let result = unifiedRepos;

  // Apply view mode filter first
  result = filterByViewMode(result, viewMode);

  // Apply quick filter
  result = filterUnifiedReposByQuickFilter(result, quickFilter);

  // Apply text filter
  if (filterText) {
    result = filterUnifiedRepos(result, filterText);
  }

  // Apply language filter
  if (languageFilter) {
    result = result.filter((repo) =>
      getUnifiedRepoLanguage(repo)?.toLowerCase() === languageFilter.toLowerCase()
    );
  }

  // Apply sort
  result = sortUnifiedRepos(result, sortBy, sortDirection);

  return result;
}

/**
 * Hook to get selected unified repos
 */
export function useSelectedUnifiedRepos() {
  const { state } = useStore();
  const filteredRepos = useFilteredUnifiedRepos();
  const { selectedIndices, cursorIndex } = state;

  // If nothing selected, return the repo at cursor
  if (selectedIndices.size === 0) {
    const current = filteredRepos[cursorIndex];
    return current ? [current] : [];
  }

  // Return selected repos (filter out undefined and properly type)
  return [...selectedIndices]
    .map((i) => filteredRepos[i])
    .filter((r): r is NonNullable<typeof r> => r !== undefined);
}
