/**
 * Issue Management React Query Hooks
 *
 * Hooks for fetching and mutating issues.
 * Uses TanStack Query for server state management.
 *
 * Note: Until backend API is implemented, these hooks use mock data.
 * The API integration points are marked for future implementation.
 *
 * @module features/issues/hooks/useIssues
 */

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import type {
  IssueSummary,
  IssueDetail,
  IssueFilters,
  IssueSort,
  IssueUpdateRequest,
  IssueBulkActionRequest,
  PaginatedIssuesResponse,
} from '../types';
import { mockIssues, mockIssueDetail } from '../mocks';

/**
 * Query keys for issues
 */
export const issueKeys = {
  all: ['issues'] as const,
  lists: () => [...issueKeys.all, 'list'] as const,
  list: (projectId: string, filters?: IssueFilters, sort?: IssueSort) =>
    [...issueKeys.lists(), projectId, filters, sort] as const,
  details: () => [...issueKeys.all, 'detail'] as const,
  detail: (issueId: string) => [...issueKeys.details(), issueId] as const,
};

/**
 * Mock filtering and sorting logic
 * This simulates server-side filtering until API is ready
 */
function filterAndSortIssues(
  issues: IssueSummary[],
  filters?: IssueFilters,
  sort?: IssueSort
): IssueSummary[] {
  let result = [...issues];

  if (filters) {
    // Search filter
    if (filters.search) {
      const searchLower = filters.search.toLowerCase();
      result = result.filter(
        (issue) =>
          issue.title.toLowerCase().includes(searchLower) ||
          issue.description.toLowerCase().includes(searchLower) ||
          issue.number.toString().includes(searchLower)
      );
    }

    // Status filter
    if (filters.status && filters.status !== 'all') {
      result = result.filter((issue) => issue.status === filters.status);
    }

    // Priority filter
    if (filters.priority && filters.priority !== 'all') {
      result = result.filter((issue) => issue.priority === filters.priority);
    }

    // Sprint filter
    if (filters.sprint && filters.sprint !== 'all') {
      if (filters.sprint === 'backlog') {
        result = result.filter((issue) => !issue.sprint);
      } else {
        result = result.filter((issue) => issue.sprint === filters.sprint);
      }
    }

    // Assignee filter
    if (filters.assignee && filters.assignee !== 'all') {
      if (filters.assignee === 'unassigned') {
        result = result.filter((issue) => !issue.assignee);
      } else {
        result = result.filter((issue) => issue.assignee?.id === filters.assignee);
      }
    }
  }

  // Sorting
  if (sort) {
    const direction = sort.direction === 'asc' ? 1 : -1;
    result.sort((a, b) => {
      switch (sort.field) {
        case 'number':
          return (a.number - b.number) * direction;
        case 'priority': {
          const priorityOrder = { critical: 4, high: 3, medium: 2, low: 1 };
          return (priorityOrder[a.priority] - priorityOrder[b.priority]) * direction;
        }
        case 'updated_at':
          return (new Date(a.updated_at).getTime() - new Date(b.updated_at).getTime()) * direction;
        case 'created_at':
          return (new Date(a.created_at).getTime() - new Date(b.created_at).getTime()) * direction;
        default:
          return 0;
      }
    });
  }

  return result;
}

/**
 * Hook to fetch paginated issues for a project
 *
 * @param projectId - Project ID
 * @param filters - Optional filters
 * @param sort - Optional sort configuration
 * @param page - Page number (1-based)
 * @param pageSize - Number of items per page
 */
export function useIssues(
  projectId: string,
  filters?: IssueFilters,
  sort?: IssueSort,
  page: number = 1,
  pageSize: number = 25
) {
  return useQuery({
    queryKey: issueKeys.list(projectId, filters, sort),
    queryFn: async (): Promise<PaginatedIssuesResponse> => {
      // TODO: Replace with actual API call when backend is ready
      // const response = await getProjectIssues({
      //   path: { project_id: projectId },
      //   query: { ...filters, ...sort, page, page_size: pageSize },
      // });

      // Simulate API delay
      await new Promise((resolve) => setTimeout(resolve, 300));

      const filteredIssues = filterAndSortIssues(mockIssues, filters, sort);
      const start = (page - 1) * pageSize;
      const paginatedIssues = filteredIssues.slice(start, start + pageSize);

      return {
        data: paginatedIssues,
        pagination: {
          total: filteredIssues.length,
          page,
          page_size: pageSize,
          total_pages: Math.ceil(filteredIssues.length / pageSize),
          has_next: start + pageSize < filteredIssues.length,
          has_prev: page > 1,
        },
      };
    },
    staleTime: 30000, // 30 seconds
  });
}

/**
 * Hook to fetch a single issue detail
 *
 * @param issueId - Issue ID
 */
export function useIssue(issueId: string) {
  return useQuery({
    queryKey: issueKeys.detail(issueId),
    queryFn: async (): Promise<IssueDetail> => {
      // TODO: Replace with actual API call when backend is ready
      // const response = await getIssue({
      //   path: { issue_id: issueId },
      // });

      // Simulate API delay
      await new Promise((resolve) => setTimeout(resolve, 200));

      // Return mock detail for any issue ID
      return {
        ...mockIssueDetail,
        id: issueId,
      };
    },
    staleTime: 30000,
    enabled: !!issueId,
  });
}

/**
 * Hook to update an issue
 */
export function useUpdateIssue() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({
      issueId,
      data,
    }: {
      issueId: string;
      data: IssueUpdateRequest;
    }): Promise<IssueDetail> => {
      // TODO: Replace with actual API call when backend is ready
      // const response = await updateIssue({
      //   path: { issue_id: issueId },
      //   body: data,
      // });

      // Simulate API delay
      await new Promise((resolve) => setTimeout(resolve, 300));

      // Return updated mock data - only apply non-label fields from data
      return {
        ...mockIssueDetail,
        id: issueId,
        title: data.title || mockIssueDetail.title,
        description: data.description || mockIssueDetail.description,
        status: data.status || mockIssueDetail.status,
        priority: data.priority || mockIssueDetail.priority,
        sprint: data.sprint !== undefined ? data.sprint : mockIssueDetail.sprint,
        due_date: data.due_date !== undefined ? data.due_date : mockIssueDetail.due_date,
      };
    },
    onSuccess: (data) => {
      // Invalidate and update cache
      queryClient.invalidateQueries({ queryKey: issueKeys.lists() });
      queryClient.setQueryData(issueKeys.detail(data.id), data);
    },
  });
}

/**
 * Hook to update issue status (optimistic update)
 */
export function useUpdateIssueStatus() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({
      issueId,
      status,
    }: {
      issueId: string;
      status: IssueUpdateRequest['status'];
    }): Promise<IssueDetail> => {
      // TODO: Replace with actual API call
      await new Promise((resolve) => setTimeout(resolve, 300));

      return {
        ...mockIssueDetail,
        id: issueId,
        status: status || mockIssueDetail.status,
      };
    },
    onMutate: async ({ issueId, status }) => {
      // Cancel outgoing refetches
      await queryClient.cancelQueries({ queryKey: issueKeys.detail(issueId) });

      // Snapshot previous value
      const previousIssue = queryClient.getQueryData<IssueDetail>(issueKeys.detail(issueId));

      // Optimistically update
      if (previousIssue && status) {
        queryClient.setQueryData(issueKeys.detail(issueId), {
          ...previousIssue,
          status,
        });
      }

      return { previousIssue };
    },
    onError: (_err, { issueId }, context) => {
      // Rollback on error
      if (context?.previousIssue) {
        queryClient.setQueryData(issueKeys.detail(issueId), context.previousIssue);
      }
    },
    onSettled: () => {
      // Invalidate lists to refetch
      queryClient.invalidateQueries({ queryKey: issueKeys.lists() });
    },
  });
}

/**
 * Hook for bulk actions on issues
 */
export function useBulkIssueAction() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (request: IssueBulkActionRequest): Promise<{ affected_count: number }> => {
      // TODO: Replace with actual API call
      await new Promise((resolve) => setTimeout(resolve, 500));

      return { affected_count: request.issue_ids.length };
    },
    onSuccess: () => {
      // Invalidate all issue queries
      queryClient.invalidateQueries({ queryKey: issueKeys.all });
    },
  });
}

/**
 * Hook to sync an issue with external tracker
 */
export function useSyncIssue() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({ issueId }: { issueId: string }): Promise<IssueSummary> => {
      // TODO: Replace with actual API call
      // const response = await syncIssue({
      //   path: { issue_id: issueId },
      //   body: { direction: 'bidirectional' },
      // });

      await new Promise((resolve) => setTimeout(resolve, 1000));

      const issue = mockIssues.find((i) => i.id === issueId);
      return {
        ...(issue || mockIssues[0]),
        sync_status: 'synced',
      };
    },
    onSuccess: (data) => {
      queryClient.invalidateQueries({ queryKey: issueKeys.lists() });
      queryClient.invalidateQueries({ queryKey: issueKeys.detail(data.id) });
    },
  });
}
