import { useState, useCallback } from 'react';
import axios from 'axios';
import {
  MyAssignment,
  MyAssignmentsResponse,
  SwapCandidate,
  SwapCandidatesResponse,
  PendingSwapResponse,
  IncomingSwapRequest,
  OutgoingSwapRequest,
  PendingReplacementResponse,
  OutgoingReplacementRequest,
  IncomingReplacementOpportunity,
} from '../types/swapReplacement';

interface UseSwapReplacementReturn {
  // My assignments (current month)
  myAssignments: MyAssignment[];
  myAssignmentsLoading: boolean;
  fetchMyAssignments: (from?: string, to?: string) => Promise<void>;

  // Swap
  swapCandidates: SwapCandidate[];
  swapCandidatesLoading: boolean;
  incomingSwaps: IncomingSwapRequest[];
  outgoingSwaps: OutgoingSwapRequest[];
  swapPendingLoading: boolean;
  swapTotalCount: number;
  fetchSwapCandidates: (assignmentId: number) => Promise<void>;
  fetchPendingSwaps: () => Promise<void>;
  requestSwap: (assignmentId: number, targetAssignmentId: number) => Promise<void>;
  acceptSwap: (assignmentId: number) => Promise<void>;
  declineSwap: (assignmentId: number) => Promise<void>;
  cancelSwap: (assignmentId: number) => Promise<void>;

  // Replacement
  outgoingReplacements: OutgoingReplacementRequest[];
  incomingReplacements: IncomingReplacementOpportunity[];
  replacementPendingLoading: boolean;
  replacementTotalCount: number;
  availableReplacementCount: number;
  fetchPendingReplacements: () => Promise<void>;
  fetchAvailableCount: () => Promise<void>;
  requestReplacement: (assignmentId: number, notes?: string) => Promise<void>;
  volunteerReplacement: (assignmentId: number) => Promise<void>;
  cancelReplacement: (assignmentId: number) => Promise<void>;

  // Shared
  actionLoading: boolean;
  error: string | null;
  clearError: () => void;
  refreshAll: () => Promise<void>;
}

export function useSwapReplacement(): UseSwapReplacementReturn {
  // My assignments
  const [myAssignments, setMyAssignments] = useState<MyAssignment[]>([]);
  const [myAssignmentsLoading, setMyAssignmentsLoading] = useState(false);

  // Swap state
  const [swapCandidates, setSwapCandidates] = useState<SwapCandidate[]>([]);
  const [swapCandidatesLoading, setSwapCandidatesLoading] = useState(false);
  const [incomingSwaps, setIncomingSwaps] = useState<IncomingSwapRequest[]>([]);
  const [outgoingSwaps, setOutgoingSwaps] = useState<OutgoingSwapRequest[]>([]);
  const [swapPendingLoading, setSwapPendingLoading] = useState(false);
  const [swapTotalCount, setSwapTotalCount] = useState(0);

  // Replacement state
  const [outgoingReplacements, setOutgoingReplacements] = useState<OutgoingReplacementRequest[]>([]);
  const [incomingReplacements, setIncomingReplacements] = useState<IncomingReplacementOpportunity[]>([]);
  const [replacementPendingLoading, setReplacementPendingLoading] = useState(false);
  const [replacementTotalCount, setReplacementTotalCount] = useState(0);
  const [availableReplacementCount, setAvailableReplacementCount] = useState(0);

  // Shared state
  const [actionLoading, setActionLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const clearError = useCallback(() => setError(null), []);

  // ---- My Assignments ----

  const fetchMyAssignments = useCallback(async (from?: string, to?: string) => {
    try {
      setMyAssignmentsLoading(true);
      const params: Record<string, string> = {};
      if (from) params.from = from;
      if (to) params.to = to;
      const response = await axios.get<MyAssignmentsResponse>(
        '/zeiterfassung/shift-replacement/my-assignments',
        { params }
      );
      setMyAssignments(response.data.assignments);
    } catch (err: any) {
      setError(err.response?.data?.message || 'Failed to load assignments');
    } finally {
      setMyAssignmentsLoading(false);
    }
  }, []);

  // ---- Swap ----

  const fetchSwapCandidates = useCallback(async (assignmentId: number) => {
    try {
      setSwapCandidatesLoading(true);
      const response = await axios.get<SwapCandidatesResponse>(
        `/zeiterfassung/shift-swap/${assignmentId}/candidates`
      );
      setSwapCandidates(response.data.candidates);
    } catch (err: any) {
      setError(err.response?.data?.message || 'Failed to load swap candidates');
    } finally {
      setSwapCandidatesLoading(false);
    }
  }, []);

  const fetchPendingSwaps = useCallback(async () => {
    try {
      setSwapPendingLoading(true);
      const response = await axios.get<PendingSwapResponse>(
        '/zeiterfassung/shift-swap/pending'
      );
      setIncomingSwaps(response.data.incoming_requests);
      setOutgoingSwaps(response.data.outgoing_requests);
      setSwapTotalCount(response.data.total_count);
    } catch (err: any) {
      setError(err.response?.data?.message || 'Failed to load swap requests');
    } finally {
      setSwapPendingLoading(false);
    }
  }, []);

  const requestSwap = useCallback(async (assignmentId: number, targetAssignmentId: number) => {
    try {
      setActionLoading(true);
      setError(null);
      await axios.post(`/zeiterfassung/shift-swap/${assignmentId}/request`, {
        target_assignment_id: targetAssignmentId,
      });
    } catch (err: any) {
      const msg = err.response?.data?.message || 'Failed to request swap';
      setError(msg);
      throw new Error(msg);
    } finally {
      setActionLoading(false);
    }
  }, []);

  const acceptSwap = useCallback(async (assignmentId: number) => {
    try {
      setActionLoading(true);
      setError(null);
      await axios.post(`/zeiterfassung/shift-swap/${assignmentId}/accept`);
    } catch (err: any) {
      const msg = err.response?.data?.message || 'Failed to accept swap';
      setError(msg);
      throw new Error(msg);
    } finally {
      setActionLoading(false);
    }
  }, []);

  const declineSwap = useCallback(async (assignmentId: number) => {
    try {
      setActionLoading(true);
      setError(null);
      await axios.post(`/zeiterfassung/shift-swap/${assignmentId}/decline`);
    } catch (err: any) {
      const msg = err.response?.data?.message || 'Failed to decline swap';
      setError(msg);
      throw new Error(msg);
    } finally {
      setActionLoading(false);
    }
  }, []);

  const cancelSwap = useCallback(async (assignmentId: number) => {
    try {
      setActionLoading(true);
      setError(null);
      await axios.delete(`/zeiterfassung/shift-swap/${assignmentId}/cancel`);
    } catch (err: any) {
      const msg = err.response?.data?.message || 'Failed to cancel swap';
      setError(msg);
      throw new Error(msg);
    } finally {
      setActionLoading(false);
    }
  }, []);

  // ---- Replacement ----

  const fetchPendingReplacements = useCallback(async () => {
    try {
      setReplacementPendingLoading(true);
      const response = await axios.get<PendingReplacementResponse>(
        '/zeiterfassung/shift-replacement/pending'
      );
      setOutgoingReplacements(response.data.outgoing_requests);
      setIncomingReplacements(response.data.incoming_opportunities);
      setReplacementTotalCount(response.data.total_count);
    } catch (err: any) {
      setError(err.response?.data?.message || 'Failed to load replacement requests');
    } finally {
      setReplacementPendingLoading(false);
    }
  }, []);

  const fetchAvailableCount = useCallback(async () => {
    try {
      const response = await axios.get<{ count: number }>(
        '/zeiterfassung/shift-replacement/available-count'
      );
      setAvailableReplacementCount(response.data.count);
    } catch {
      // Silent fail for badge count
    }
  }, []);

  const requestReplacement = useCallback(async (assignmentId: number, notes?: string) => {
    try {
      setActionLoading(true);
      setError(null);
      await axios.post(`/zeiterfassung/shift-replacement/${assignmentId}/request`, {
        notes: notes || null,
      });
    } catch (err: any) {
      const msg = err.response?.data?.message || 'Failed to request replacement';
      setError(msg);
      throw new Error(msg);
    } finally {
      setActionLoading(false);
    }
  }, []);

  const volunteerReplacement = useCallback(async (assignmentId: number) => {
    try {
      setActionLoading(true);
      setError(null);
      await axios.post(`/zeiterfassung/shift-replacement/${assignmentId}/volunteer`);
    } catch (err: any) {
      const msg = err.response?.data?.message || 'Failed to volunteer';
      setError(msg);
      throw new Error(msg);
    } finally {
      setActionLoading(false);
    }
  }, []);

  const cancelReplacement = useCallback(async (assignmentId: number) => {
    try {
      setActionLoading(true);
      setError(null);
      await axios.delete(`/zeiterfassung/shift-replacement/${assignmentId}/cancel`);
    } catch (err: any) {
      const msg = err.response?.data?.message || 'Failed to cancel replacement';
      setError(msg);
      throw new Error(msg);
    } finally {
      setActionLoading(false);
    }
  }, []);

  // ---- Refresh All ----

  const refreshAll = useCallback(async () => {
    await Promise.all([
      fetchMyAssignments(),
      fetchPendingSwaps(),
      fetchPendingReplacements(),
      fetchAvailableCount(),
    ]);
  }, [fetchMyAssignments, fetchPendingSwaps, fetchPendingReplacements, fetchAvailableCount]);

  return {
    myAssignments,
    myAssignmentsLoading,
    fetchMyAssignments,

    swapCandidates,
    swapCandidatesLoading,
    incomingSwaps,
    outgoingSwaps,
    swapPendingLoading,
    swapTotalCount,
    fetchSwapCandidates,
    fetchPendingSwaps,
    requestSwap,
    acceptSwap,
    declineSwap,
    cancelSwap,

    outgoingReplacements,
    incomingReplacements,
    replacementPendingLoading,
    replacementTotalCount,
    availableReplacementCount,
    fetchPendingReplacements,
    fetchAvailableCount,
    requestReplacement,
    volunteerReplacement,
    cancelReplacement,

    actionLoading,
    error,
    clearError,
    refreshAll,
  };
}

export default useSwapReplacement;
