import { Dispatch, SetStateAction, useCallback } from 'react';
import { toast } from 'sonner';
import { onboardingService } from '@/services/onboarding.service';

interface UseApplicationDetailsAdminActionsParams {
  application: any;
  applicationId: string;
  currentUser: any;
  interviews: any[];
  approvalFile: File | null;
  approvalRemark: string;
  rejectionReason: string;
  architectureLeadId: string;
  architectureStatus: string;
  architectureRemarks: string;
  selectedUser: string;
  participantType: string;
  users: any[];
  interviewDate: string;
  setInterviewDate: Dispatch<SetStateAction<string>>;
  interviewType: string;
  setInterviewType: Dispatch<SetStateAction<string>>;
  interviewMode: string;
  setInterviewMode: Dispatch<SetStateAction<string>>;
  meetingLink: string;
  setMeetingLink: Dispatch<SetStateAction<string>>;
  location: string;
  setLocation: Dispatch<SetStateAction<string>>;
  scheduledInterviewParticipants: any[];
  uploadFile: File | null;
  uploadDocType: string;
  selectedStage: string | null;
  setIsApproving: Dispatch<SetStateAction<boolean>>;
  setShowApproveModal: Dispatch<SetStateAction<boolean>>;
  setApprovalRemark: Dispatch<SetStateAction<string>>;
  setApprovalFile: Dispatch<SetStateAction<File | null>>;
  setIsRejecting: Dispatch<SetStateAction<boolean>>;
  setShowRejectModal: Dispatch<SetStateAction<boolean>>;
  setRejectionReason: Dispatch<SetStateAction<string>>;
  setIsAssigningArchitecture: Dispatch<SetStateAction<boolean>>;
  setShowAssignArchitectureModal: Dispatch<SetStateAction<boolean>>;
  setIsUpdatingArchitecture: Dispatch<SetStateAction<boolean>>;
  setShowArchitectureStatusModal: Dispatch<SetStateAction<boolean>>;
  setIsAssigningParticipant: Dispatch<SetStateAction<boolean>>;
  setSelectedUser: Dispatch<SetStateAction<string>>;
  setShowAssignModal: Dispatch<SetStateAction<boolean>>;
  setLoading: Dispatch<SetStateAction<boolean>>;
  setIsScheduling: Dispatch<SetStateAction<boolean>>;
  setShowScheduleModal: Dispatch<SetStateAction<boolean>>;
  setShowCancelInterviewModal: Dispatch<SetStateAction<boolean>>;
  interviewIdToCancel: string;
  setInterviewIdToCancel: Dispatch<SetStateAction<string>>;
  interviewToReschedule: any;
  setInterviewToReschedule: Dispatch<SetStateAction<any>>;
  setIsCancellingInterview: Dispatch<SetStateAction<boolean>>;
  setIsUploading: Dispatch<SetStateAction<boolean>>;
  setShowUploadForm: Dispatch<SetStateAction<boolean>>;
  setUploadFile: Dispatch<SetStateAction<File | null>>;
  setUploadDocType: Dispatch<SetStateAction<string>>;
  setDocuments: Dispatch<SetStateAction<any[]>>;
  selectedInterviewerId: string;
  setSelectedInterviewerId: Dispatch<SetStateAction<string>>;
  setScheduledInterviewParticipants: Dispatch<SetStateAction<any[]>>;
  setUsers: Dispatch<SetStateAction<any[]>>;
  showScheduleModal: boolean;
  showAssignArchitectureModal: boolean;
  showAssignModal: boolean;
  fetchApplication: (silent?: boolean) => Promise<void>;
  fetchInterviews: () => Promise<void>;
  fetchEorData: () => Promise<void>;
}

export function useApplicationDetailsAdminActions(params: UseApplicationDetailsAdminActionsParams) {
  const {
    application,
    applicationId,
    currentUser,
    interviews,
    approvalFile,
    approvalRemark,
    rejectionReason,
    architectureLeadId,
    architectureStatus,
    architectureRemarks,
    selectedUser,
    participantType,
    users,
    interviewDate,
    setInterviewDate,
    interviewType,
    setInterviewType,
    interviewMode,
    setInterviewMode,
    meetingLink,
    setMeetingLink,
    location,
    setLocation,
    scheduledInterviewParticipants,
    uploadFile,
    uploadDocType,
    selectedStage,
    setIsApproving,
    setShowApproveModal,
    setApprovalRemark,
    setApprovalFile,
    setIsRejecting,
    setShowRejectModal,
    setRejectionReason,
    setIsAssigningArchitecture,
    setShowAssignArchitectureModal,
    setIsUpdatingArchitecture,
    setShowArchitectureStatusModal,
    setIsAssigningParticipant,
    setSelectedUser,
    setShowAssignModal,
    setLoading,
    setIsScheduling,
    setShowScheduleModal,
    setShowCancelInterviewModal,
    interviewIdToCancel,
    setInterviewIdToCancel,
    interviewToReschedule,
    setInterviewToReschedule,
    setIsCancellingInterview,
    setIsUploading,
    setShowUploadForm,
    setUploadFile,
    setUploadDocType,
    setDocuments,
    selectedInterviewerId,
    setSelectedInterviewerId,
    setScheduledInterviewParticipants,
    setUsers,
    showScheduleModal,
    showAssignArchitectureModal,
    showAssignModal,
    fetchApplication,
    fetchInterviews,
    fetchEorData,
  } = params;

  const handleAddInterviewer = () => {
    if (!selectedInterviewerId) return;
    const usersList = Array.isArray(users) ? users : [];
    const userToAdd = usersList.find((u) => u.id === selectedInterviewerId);
    if (userToAdd && !scheduledInterviewParticipants.find((p) => p.id === userToAdd.id)) {
      setScheduledInterviewParticipants([...scheduledInterviewParticipants, userToAdd]);
      setSelectedInterviewerId('');
    }
  };

  const handleRemoveInterviewer = (userId: string) => {
    setScheduledInterviewParticipants(scheduledInterviewParticipants.filter((p) => p.id !== userId));
  };

  const fetchUsers = useCallback(async (type?: string) => {
    if (!currentUser || !['DD Admin', 'Super Admin', 'DD Lead', 'DD Head', 'NBH'].includes(currentUser.role)) return;
    try {
      const reqParams: any = {};
      if (type) {
        const roleMapping: any = {
          level1: ['DD-ZM', 'RBM'],
          level2: ['DD Lead', 'ZBH'],
          level3: ['NBH', 'DD Head'],
        };
        // Keep stage roles as preferred default, but allow broader user pool
        // so admins can add extra panelists for the same interview.
        if (roleMapping[type]) {
          reqParams.preferredRoleCode = roleMapping[type];
        }
        if (application) {
          reqParams.locationId = application.districtId || application.areaId || application.regionId || application.zoneId;
        }
      }
      reqParams.isExternal = false;
      const response = await onboardingService.getUsers(reqParams);
      const rawUsers = Array.isArray(response)
        ? response
        : response && Array.isArray(response.data)
          ? response.data
          : response && Array.isArray(response.users)
            ? response.users
            : [];
      // Exclude inactive users and keep deterministic sorting.
      const activeUsers = rawUsers.filter((u: any) => (u.status || '').toLowerCase() !== 'inactive');
      setUsers(activeUsers.sort((a: any, b: any) => String(a.fullName || a.name || '').localeCompare(String(b.fullName || b.name || ''))));
    } catch {
      setUsers([]);
    }
  }, [currentUser, application, setUsers]);

  const prefillInterviewParticipants = useCallback(() => {
    if (!showScheduleModal || !application || interviewToReschedule) return;
    const levelNum = parseInt(interviewType.replace('level', '')) || 1;
    const requiredRolesByLevel: Record<number, string[]> = {
      1: ['DD-ZM', 'RBM'],
      2: ['DD Lead', 'ZBH'],
      3: ['NBH', 'DD Head'],
    };
    const normalizeRole = (value: unknown) =>
      String(value || '')
        .trim()
        .toLowerCase()
        .replace(/[_\s-]+/g, ' ');
    const expectedRoles = (requiredRolesByLevel[levelNum] || []).map(normalizeRole);

    const deriveDisplayRole = (participant: any, user: any): string => {
      const candidateRoles = [
        participant?.metadata?.role,
        user?.role?.roleName,
        user?.role?.roleCode,
        user?.roleCode,
        user?.role,
      ].filter(Boolean);
      const matched = candidateRoles.find((r: any) => expectedRoles.includes(normalizeRole(r)));
      return String(matched || candidateRoles[0] || 'Panelist');
    };

    const preAssigned = (application?.participants || [])
      .filter((p: any) =>
        p.metadata?.interviewLevel === levelNum ||
        p.metadata?.interviewLevel === String(levelNum) ||
        p.metadata?.allAssignments?.includes(levelNum) ||
        p.metadata?.allAssignments?.includes(String(levelNum)) ||
        expectedRoles.includes(normalizeRole(p.user?.role)) ||
        expectedRoles.includes(normalizeRole(p.user?.roleCode)) ||
        expectedRoles.includes(normalizeRole(p.metadata?.role))
      )
      .map((p: any) => {
        const user = p.user || {};
        return {
          ...user,
          __stageRole: deriveDisplayRole(p, user),
        };
      })
      .filter((u: any) => !!u?.id);
    if (preAssigned.length === 0) {
      setScheduledInterviewParticipants([]);
      return;
    }
    const unique: any[] = [];
    const seen = new Set();
    preAssigned.forEach((u: any) => {
      if (u.id && !seen.has(u.id)) {
        seen.add(u.id);
        unique.push(u);
      }
    });
    setScheduledInterviewParticipants(unique);
  }, [showScheduleModal, application, interviewType, interviewToReschedule, setScheduledInterviewParticipants]);

  const handleScheduleInterview = async () => {
    if (!interviewDate) {
      toast.warning('Please select date and time');
      return;
    }
    try {
      setIsScheduling(true);
      const payload = {
        applicationId: application?.id,
        level: interviewType,
        scheduledAt: interviewDate,
        type: interviewMode === 'virtual' ? 'Virtual Interview' : 'Physical Interview',
        location: interviewMode === 'virtual' ? meetingLink : location,
        participants: scheduledInterviewParticipants.map((p) => p.id),
      };

      if (interviewToReschedule) {
        await onboardingService.updateInterview(interviewToReschedule.id, {
          ...payload,
          status: 'Scheduled',
        });
        toast.success('Interview rescheduled successfully');
      } else {
        await onboardingService.scheduleInterview(payload);
        toast.success('Interview scheduled successfully');
      }

      setShowScheduleModal(false);
      setInterviewToReschedule(null);
      await fetchInterviews();
      await fetchApplication();
    } catch {
      toast.error(interviewToReschedule ? 'Failed to reschedule interview' : 'Failed to schedule interview');
    } finally {
      setIsScheduling(false);
    }
  };

  const handleCancelInterview = async (interviewId: string) => {
    setInterviewIdToCancel(interviewId);
    setShowCancelInterviewModal(true);
  };

  const handleRescheduleInterview = async (interview: any) => {
    setInterviewToReschedule(interview);
    setInterviewType(`level${interview.level}`);
    setInterviewMode(interview.interviewType?.toLowerCase().includes('virtual') ? 'virtual' : 'physical');
    setInterviewDate(interview.scheduleDate ? (() => {
      const d = new Date(interview.scheduleDate);
      return new Date(d.getTime() - d.getTimezoneOffset() * 60000).toISOString().slice(0, 16);
    })() : '');
    if (interview.interviewType?.toLowerCase().includes('virtual')) {
      setMeetingLink(interview.linkOrLocation || '');
    } else {
      setLocation(interview.linkOrLocation || '');
    }
    const participants = (interview.participants || []).map((p: any) => p.user || p).filter(Boolean);
    setScheduledInterviewParticipants(participants);
    setShowScheduleModal(true);
  };

  const handleConfirmCancelInterview = async () => {
    if (!interviewIdToCancel) return;
    try {
      setIsCancellingInterview(true);
      await onboardingService.updateInterview(interviewIdToCancel, { status: 'Cancelled' });
      toast.success('Interview cancelled successfully');
      setShowCancelInterviewModal(false);
      setInterviewIdToCancel('');
      await fetchInterviews();
    } catch {
      toast.error('Failed to cancel interview');
    } finally {
      setIsCancellingInterview(false);
    }
  };

  const handleUpload = async () => {
    if (!uploadFile || !uploadDocType) {
      toast.warning('Please select a file and document type');
      return;
    }
    try {
      setIsUploading(true);
      const formData = new FormData();
      formData.append('file', uploadFile);
      formData.append('documentType', uploadDocType);
      if (selectedStage) formData.append('stage', selectedStage);
      await onboardingService.uploadDocument(applicationId, formData);
      toast.success('Document uploaded successfully');
      setShowUploadForm(false);
      setUploadFile(null);
      setUploadDocType('');
      const docs = await onboardingService.getDocuments(applicationId);
      setDocuments(docs || []);
      await fetchEorData();
    } catch {
      toast.error('Failed to upload document');
    } finally {
      setIsUploading(false);
    }
  };

  const handleApprove = async () => {
    try {
      setIsApproving(true);
      const activeInterview = interviews.find((i) =>
        i.status !== 'Completed' &&
        i.status !== 'Cancelled' &&
        i.participants?.some((p: any) => p.userId === currentUser?.id)
      );

      if (approvalFile && applicationId) {
        try {
          const formData = new FormData();
          formData.append('file', approvalFile);
          formData.append('documentType', 'Approval Attachment');
          let stageName: string | null = null;
          if (activeInterview) {
            if (activeInterview.level === 1 || activeInterview.level === '1') stageName = '1st Level Interview';
            else if (activeInterview.level === 2 || activeInterview.level === '2') stageName = '2nd Level Interview';
            else if (activeInterview.level === 3 || activeInterview.level === '3') stageName = '3rd Level Interview';
          }
          if (!stageName) {
            if (application.status === 'Shortlisted' || application.status === 'Level 1 Interview Pending') stageName = '1st Level Interview';
            else if (application.status === 'Level 1 Approved' || application.status === 'Level 2 Interview Pending') stageName = '2nd Level Interview';
            else if (application.status === 'Level 2 Approved' || application.status === 'Level 3 Interview Pending') stageName = '3rd Level Interview';
          }
          if (stageName) formData.append('stage', stageName);
          await onboardingService.uploadDocument(applicationId, formData);
        } catch {
          toast.error('Failed to upload document');
        }
      }

      if (activeInterview) {
        try {
          await onboardingService.updateInterviewDecision({ interviewId: activeInterview.id, decision: 'Approved', remarks: approvalRemark });
          toast.success('Interview approved successfully');
          setShowApproveModal(false);
          setApprovalRemark('');
          setApprovalFile(null);
          await fetchInterviews();
          await fetchApplication();
          return;
        } catch {
          toast.error('Failed to approve interview');
          return;
        }
      }

      if (!approvalRemark.trim()) {
        toast.warning('Please enter a remark');
        return;
      }

      let newStatus = application.status;
      switch (application.status) {
        case 'Shortlisted':
        case 'Level 1 Interview Pending': newStatus = 'Level 1 Approved'; break;
        case 'Level 1 Approved':
        case 'Level 2 Interview Pending': newStatus = 'Level 2 Approved'; break;
        case 'Level 2 Approved':
        case 'Level 3 Interview Pending': newStatus = 'Level 3 Approved'; break;
        case 'Level 3 Approved': newStatus = 'FDD Verification'; break;
        case 'FDD Verification': newStatus = 'LOI In Progress'; break;
        case 'LOI In Progress': newStatus = 'Security Details'; break;
        case 'Security Details':
        case 'Payment Pending': newStatus = 'LOI Issued'; break;
        case 'LOI Issued': newStatus = 'Dealer Code Generation'; break;
        case 'Dealer Code Generation':
        case 'Architecture Team Assigned':
        case 'Architecture Document Upload':
        case 'Architecture Team Completion':
        case 'Statutory GST':
        case 'Statutory PAN':
        case 'Statutory Nodal':
        case 'Statutory Check':
        case 'Statutory Partnership':
        case 'Statutory Firm Reg':
        case 'Statutory Rental':
        case 'Statutory Virtual Code':
        case 'Statutory Domain':
        case 'Statutory MSD':
        case 'Statutory LOI Ack': newStatus = 'LOA Pending'; break;
        case 'LOA Pending': newStatus = 'EOR In Progress'; break;
        case 'EOR In Progress': newStatus = 'EOR Complete'; break;
        case 'EOR Complete': newStatus = 'Inauguration'; break;
        case 'Inauguration':
        case 'Approved': newStatus = 'Onboarded'; break;
        default: newStatus = 'Onboarded';
      }

      const policyManagedStages: Record<string, string> = {
        'Level 1 Interview Pending': 'INTERVIEW_LEVEL_1',
        'Level 2 Interview Pending': 'INTERVIEW_LEVEL_2',
        'Level 2 Recommended': 'INTERVIEW_LEVEL_2',
        'Level 3 Interview Pending': 'INTERVIEW_LEVEL_3',
        'LOI In Progress': 'LOI_APPROVAL',
        'LOA Pending': 'LOA_APPROVAL',
      };

      const stageCodeForPolicy = policyManagedStages[application.status];
      if (stageCodeForPolicy) {
        const response = await onboardingService.submitStageDecision({
          applicationId: application.id,
          stageCode: stageCodeForPolicy,
          decision: 'Approved',
          remarks: approvalRemark,
          nextStatus: newStatus,
        });
        if (response.data?.statusUpdated) toast.success(response.message || 'Stage completed and moved to next step');
        else toast.info(response.message || 'Approval recorded. Waiting for other mandatory approvers.');
      } else {
        await onboardingService.updateApplicationStatus(applicationId, { status: newStatus, remarks: approvalRemark });
      }

      if (newStatus === 'Onboarded') {
        await onboardingService.createDealer({ applicationId });
        toast.success('Application finalized and Dealer profile created!');
      } else {
        toast.success(`Application moved to ${newStatus}`);
      }

      setShowApproveModal(false);
      setApprovalRemark('');
      setApprovalFile(null);
      await fetchApplication();
    } catch (error: any) {
      toast.error(error.message || 'Failed to process approval');
    } finally {
      setIsApproving(false);
    }
  };

  const handleReject = async () => {
    try {
      setIsRejecting(true);
      const activeInterview = interviews.find((i) =>
        i.status !== 'Completed' &&
        i.status !== 'Cancelled' &&
        i.participants?.some((p: any) => p.userId === currentUser?.id)
      );
      if (activeInterview) {
        try {
          await onboardingService.updateInterviewDecision({ interviewId: activeInterview.id, decision: 'Rejected', remarks: rejectionReason });
          toast.success('Interview rejected');
          setShowRejectModal(false);
          setRejectionReason('');
          await fetchInterviews();
          await fetchApplication();
          return;
        } catch {
          toast.error('Failed to reject interview');
          return;
        }
      }
      if (!rejectionReason.trim()) {
        toast.warning('Please enter a reason for rejection');
        return;
      }
      const policyManagedStages: Record<string, string> = {
        'Level 1 Interview Pending': 'INTERVIEW_LEVEL_1',
        'Level 2 Interview Pending': 'INTERVIEW_LEVEL_2',
        'Level 2 Recommended': 'INTERVIEW_LEVEL_2',
        'Level 3 Interview Pending': 'INTERVIEW_LEVEL_3',
        'LOI In Progress': 'LOI_APPROVAL',
        'LOA Pending': 'LOA_APPROVAL',
      };
      const stageCodeForPolicy = policyManagedStages[application.status];
      if (stageCodeForPolicy) {
        await onboardingService.submitStageDecision({
          applicationId: application.id,
          stageCode: stageCodeForPolicy,
          decision: 'Rejected',
          remarks: rejectionReason,
          interviewId: activeInterview?.id,
        });
      } else {
        await onboardingService.updateApplicationStatus(applicationId, { status: 'Rejected', remarks: rejectionReason });
      }
      toast.success('Application rejected');
      setShowRejectModal(false);
      setRejectionReason('');
      await fetchApplication();
    } catch (error: any) {
      toast.error(error.message || 'Failed to process rejection');
    } finally {
      setIsRejecting(false);
    }
  };

  const handleGenerateDealerCodes = async () => {
    try {
      await onboardingService.generateDealerCodes(applicationId);
      toast.success('Dealer codes generated successfully');
      await fetchApplication();
    } catch (error: any) {
      toast.error(error.message || 'Failed to generate dealer codes');
    }
  };

  const handleAssignArchitecture = async () => {
    if (!architectureLeadId) {
      toast.warning('Please select an architecture lead');
      return;
    }
    try {
      setIsAssigningArchitecture(true);
      await onboardingService.assignArchitectureTeam(applicationId, architectureLeadId);
      toast.success('Architecture team assigned successfully');
      setShowAssignArchitectureModal(false);
      await fetchApplication();
    } catch (error: any) {
      toast.error(error.message || 'Failed to assign architecture team');
    } finally {
      setIsAssigningArchitecture(false);
    }
  };

  const handleUpdateArchitectureStatus = async () => {
    try {
      setIsUpdatingArchitecture(true);
      await onboardingService.updateArchitectureStatus(applicationId, architectureStatus, architectureRemarks);
      toast.success('Architecture status updated successfully');
      setShowArchitectureStatusModal(false);
      await fetchApplication();
    } catch {
      toast.error('Failed to update architecture status');
    } finally {
      setIsUpdatingArchitecture(false);
    }
  };

  const handleAddParticipant = async () => {
    if (!selectedUser) {
      toast.warning('Please select a user');
      return;
    }
    try {
      setIsAssigningParticipant(true);
      const u = Array.isArray(users) ? users.find((user) => user.id === selectedUser) : null;
      if (u && (u.role === 'FDD' || u.roleCode === 'FDD')) {
        await onboardingService.assignFddAgency({ applicationId, assignedToAgency: selectedUser });
        toast.info(`${u.fullName || u.name} assigned as FDD Agency based on role.`);
      }
      await onboardingService.addParticipant({
        requestId: applicationId,
        requestType: 'application',
        userId: selectedUser,
        participantType: participantType || 'contributor',
      });
      toast.success('User assigned successfully!');
      await fetchApplication();
      setSelectedUser('');
      setShowAssignModal(false);
    } catch {
      toast.error('Failed to assign user');
    } finally {
      setIsAssigningParticipant(false);
    }
  };

  const handleRetriggerEvaluators = async () => {
    try {
      setLoading(true);
      await onboardingService.retriggerEvaluators(applicationId);
      toast.success('Evaluators re-assigned successfully');
      await fetchApplication();
    } catch {
      toast.error('Failed to re-assign evaluators');
    } finally {
      setLoading(false);
    }
  };

  const maybeFetchUsersForModal = useCallback(async () => {
    if (showScheduleModal && application) {
      await fetchUsers(interviewType);
      prefillInterviewParticipants();
      return;
    }
    if ((showAssignArchitectureModal || showAssignModal) && application) {
      await fetchUsers();
    }
  }, [
    showScheduleModal,
    showAssignArchitectureModal,
    showAssignModal,
    application,
    interviewType,
    fetchUsers,
    prefillInterviewParticipants,
  ]);

  return {
    handleAddInterviewer,
    handleRemoveInterviewer,
    fetchUsers,
    maybeFetchUsersForModal,
    handleScheduleInterview,
    handleRescheduleInterview,
    handleCancelInterview,
    handleConfirmCancelInterview,
    handleUpload,
    handleApprove,
    handleReject,
    handleGenerateDealerCodes,
    handleAssignArchitecture,
    handleUpdateArchitectureStatus,
    handleAddParticipant,
    handleRetriggerEvaluators,
  };
}
