/**
 * Claim Data Mapper Utilities
 * Maps API response data to ClaimManagementRequest structure for frontend components
 */

import { isClaimManagementRequest } from './claimRequestUtils';

/**
 * User roles in a claim management request
 */
export type RequestRole = 'INITIATOR' | 'DEALER' | 'DEPARTMENT_LEAD' | 'APPROVER' | 'SPECTATOR';

/**
 * Claim Management Request structure for frontend
 */
export interface ClaimManagementRequest {
  // Activity Information
  activityInfo: {
    activityName: string;
    activityType: string;
    requestedDate?: string;
    location: string;
    period?: {
      startDate: string;
      endDate: string;
    };
    estimatedBudget?: number;
    closedExpenses?: number;
    closedExpensesBreakdown?: Array<{ description: string; amount: number }>;
    description?: string;
  };

  // Dealer Information
  dealerInfo: {
    dealerCode: string;
    dealerName: string;
    email?: string;
    phone?: string;
    address?: string;
  };

  // Proposal Details (Step 1)
  proposalDetails?: {
    proposalDocumentUrl?: string;
    costBreakup: Array<{ description: string; amount: number }>;
    totalEstimatedBudget: number;
    timelineMode?: 'date' | 'days';
    expectedCompletionDate?: string;
    expectedCompletionDays?: number;
    dealerComments?: string;
    submittedAt?: string;
  };

  // IO Details (Step 3) - from internal_orders table
  ioDetails?: {
    ioNumber?: string;
    ioRemark?: string;
    availableBalance?: number;
    blockedAmount?: number;
    remainingBalance?: number;
    organizedBy?: string;
    organizedAt?: string;
  };

  // DMS Details (Step 7)
  dmsDetails?: {
    eInvoiceNumber?: string;
    eInvoiceDate?: string;
    dmsNumber?: string;
    creditNoteNumber?: string;
    creditNoteDate?: string;
    creditNoteAmount?: number;
  };

  // Claim Amount
  claimAmount: {
    estimated: number;
    closed: number;
  };
}

/**
 * Role-based visibility configuration
 */
export interface RoleVisibility {
  showDealerInfo: boolean;
  showProposalDetails: boolean;
  showIODetails: boolean;
  showDMSDetails: boolean;
  showClaimAmount: boolean;
  canEditClaimAmount: boolean;
}

/**
 * Map API request data to ClaimManagementRequest structure
 */
export function mapToClaimManagementRequest(
  apiRequest: any,
  _currentUserId: string
): ClaimManagementRequest | null {
  try {
    if (!isClaimManagementRequest(apiRequest)) {
      return null;
    }

    // Extract claim details from API response
    const claimDetails = apiRequest.claimDetails || {};
    const proposalDetails = apiRequest.proposalDetails || {};
    const completionDetails = apiRequest.completionDetails || {};
    const internalOrder = apiRequest.internalOrder || apiRequest.internal_order || {};
    
    // Extract new normalized tables
    const budgetTracking = apiRequest.budgetTracking || apiRequest.budget_tracking || {};
    const invoice = apiRequest.invoice || {};
    const creditNote = apiRequest.creditNote || apiRequest.credit_note || {};
    const completionExpenses = apiRequest.completionExpenses || apiRequest.completion_expenses || [];

    // Debug: Log raw claim details to help troubleshoot
    console.debug('[claimDataMapper] Raw claimDetails:', claimDetails);
    console.debug('[claimDataMapper] Raw apiRequest:', {
      hasClaimDetails: !!apiRequest.claimDetails,
      hasProposalDetails: !!apiRequest.proposalDetails,
      hasCompletionDetails: !!apiRequest.completionDetails,
      hasBudgetTracking: !!budgetTracking,
      hasInvoice: !!invoice,
      hasCreditNote: !!creditNote,
      hasCompletionExpenses: Array.isArray(completionExpenses) && completionExpenses.length > 0,
      workflowType: apiRequest.workflowType,
    });

    // Map activity information (matching ActivityInformationCard expectations)
    // Handle both camelCase and snake_case field names from Sequelize
    const periodStartDate = claimDetails.periodStartDate || claimDetails.period_start_date;
    const periodEndDate = claimDetails.periodEndDate || claimDetails.period_end_date;
    
    const activityName = claimDetails.activityName || claimDetails.activity_name || '';
    const activityType = claimDetails.activityType || claimDetails.activity_type || '';
    const location = claimDetails.location || '';
    
    console.debug('[claimDataMapper] Mapped activity fields:', {
      activityName,
      activityType,
      location,
      hasActivityName: !!activityName,
      hasActivityType: !!activityType,
      hasLocation: !!location,
    });
    
    // Get budget values from budgetTracking table (new source of truth)
    const estimatedBudget = budgetTracking.proposalEstimatedBudget || 
                           budgetTracking.proposal_estimated_budget ||
                           budgetTracking.initialEstimatedBudget ||
                           budgetTracking.initial_estimated_budget ||
                           claimDetails.estimatedBudget || 
                           claimDetails.estimated_budget;

    // Get closed expenses - check multiple sources with proper number conversion
    const closedExpensesRaw = budgetTracking?.closedExpenses || 
                          budgetTracking?.closed_expenses ||
                          completionDetails?.totalClosedExpenses ||
                          completionDetails?.total_closed_expenses ||
                          claimDetails?.closedExpenses || 
                          claimDetails?.closed_expenses;
    // Convert to number and handle 0 as valid value
    const closedExpenses = closedExpensesRaw !== null && closedExpensesRaw !== undefined 
      ? Number(closedExpensesRaw) 
      : undefined;

    // Get closed expenses breakdown from new completionExpenses table
    const closedExpensesBreakdown = Array.isArray(completionExpenses) && completionExpenses.length > 0
      ? completionExpenses.map((exp: any) => ({
          description: exp.description || exp.itemDescription || '',
          amount: Number(exp.amount) || 0
        }))
      : (completionDetails?.closedExpenses || 
         completionDetails?.closed_expenses ||
         completionDetails?.closedExpensesBreakdown ||
         []);
    
    const activityInfo = {
      activityName,
      activityType,
      requestedDate: claimDetails.activityDate || claimDetails.activity_date || apiRequest.createdAt, // Use activityDate as requestedDate, fallback to createdAt
      location,
      period: (periodStartDate && periodEndDate) ? {
        startDate: periodStartDate,
        endDate: periodEndDate,
      } : undefined,
      estimatedBudget,
      closedExpenses,
      closedExpensesBreakdown,
      description: apiRequest.description || '', // Get description from workflow request
    };

    // Map dealer information (matching DealerInformationCard expectations)
    // Dealer info should always be available from claimDetails (created during claim request creation)
    // Handle both camelCase and snake_case from Sequelize JSON serialization
    const dealerInfo = {
      dealerCode: claimDetails?.dealerCode || claimDetails?.dealer_code || claimDetails?.DealerCode || '',
      dealerName: claimDetails?.dealerName || claimDetails?.dealer_name || claimDetails?.DealerName || '',
      email: claimDetails?.dealerEmail || claimDetails?.dealer_email || claimDetails?.DealerEmail || '',
      phone: claimDetails?.dealerPhone || claimDetails?.dealer_phone || claimDetails?.DealerPhone || '',
      address: claimDetails?.dealerAddress || claimDetails?.dealer_address || claimDetails?.DealerAddress || '',
    };

    // Log warning if dealer info is missing (should always be present for claim management requests)
    if (!dealerInfo.dealerCode || !dealerInfo.dealerName) {
      console.warn('[claimDataMapper] Dealer information is missing from claimDetails:', {
        hasClaimDetails: !!claimDetails,
        dealerCode: dealerInfo.dealerCode,
        dealerName: dealerInfo.dealerName,
        rawClaimDetails: claimDetails,
        availableKeys: claimDetails ? Object.keys(claimDetails) : [],
      });
    }

    // Map proposal details
    const expectedCompletionDate = proposalDetails?.expectedCompletionDate || proposalDetails?.expected_completion_date;
    const proposal = proposalDetails ? {
      proposalDocumentUrl: proposalDetails.proposalDocumentUrl || proposalDetails.proposal_document_url,
      costBreakup: proposalDetails.costBreakup || proposalDetails.cost_breakup || [],
      totalEstimatedBudget: proposalDetails.totalEstimatedBudget || proposalDetails.total_estimated_budget || 0,
      timelineMode: proposalDetails.timelineMode || proposalDetails.timeline_mode,
      expectedCompletionDate: expectedCompletionDate,
      expectedCompletionDays: proposalDetails.expectedCompletionDays || proposalDetails.expected_completion_days,
      timelineForClosure: expectedCompletionDate, // Map expectedCompletionDate to timelineForClosure for ProposalDetailsCard
      dealerComments: proposalDetails.dealerComments || proposalDetails.dealer_comments,
      submittedOn: proposalDetails.submittedAt || proposalDetails.submitted_at || proposalDetails.submittedOn,
    } : undefined;

    // Map IO details from dedicated internal_orders table
    const ioDetails = {
      ioNumber: internalOrder.ioNumber || internalOrder.io_number || claimDetails.ioNumber || claimDetails.io_number,
      ioRemark: internalOrder.ioRemark || internalOrder.io_remark || '',
      availableBalance: internalOrder.ioAvailableBalance || internalOrder.io_available_balance || claimDetails.ioAvailableBalance || claimDetails.io_available_balance,
      blockedAmount: internalOrder.ioBlockedAmount || internalOrder.io_blocked_amount || claimDetails.ioBlockedAmount || claimDetails.io_blocked_amount,
      remainingBalance: internalOrder.ioRemainingBalance || internalOrder.io_remaining_balance || claimDetails.ioRemainingBalance || claimDetails.io_remaining_balance,
      organizedBy: internalOrder.organizer?.displayName || internalOrder.organizer?.name || internalOrder.organizedBy || '',
      organizedAt: internalOrder.organizedAt || internalOrder.organized_at || '',
    };

    // Map DMS details from new invoice and credit note tables
    const dmsDetails = {
      eInvoiceNumber: invoice.invoiceNumber || invoice.invoice_number || 
                     claimDetails.eInvoiceNumber || claimDetails.e_invoice_number,
      eInvoiceDate: invoice.invoiceDate || invoice.invoice_date || 
                   claimDetails.eInvoiceDate || claimDetails.e_invoice_date,
      dmsNumber: invoice.dmsNumber || invoice.dms_number || 
                claimDetails.dmsNumber || claimDetails.dms_number,
      creditNoteNumber: creditNote.creditNoteNumber || creditNote.credit_note_number || 
                       claimDetails.creditNoteNumber || claimDetails.credit_note_number,
      creditNoteDate: creditNote.creditNoteDate || creditNote.credit_note_date || 
                     claimDetails.creditNoteDate || claimDetails.credit_note_date,
      creditNoteAmount: creditNote.creditNoteAmount ? Number(creditNote.creditNoteAmount) : 
                       (creditNote.credit_note_amount ? Number(creditNote.credit_note_amount) :
                       (creditNote.creditNoteAmount ? Number(creditNote.creditNoteAmount) :
                       (claimDetails.creditNoteAmount ? Number(claimDetails.creditNoteAmount) :
                       (claimDetails.credit_note_amount ? Number(claimDetails.credit_note_amount) : undefined)))),
    };

    // Map claim amounts
    const claimAmount = {
      estimated: activityInfo.estimatedBudget || 0,
      closed: activityInfo.closedExpenses || 0,
    };

    return {
      activityInfo,
      dealerInfo,
      proposalDetails: proposal,
      ioDetails: Object.keys(ioDetails).some(k => ioDetails[k as keyof typeof ioDetails]) ? ioDetails : undefined,
      dmsDetails: Object.keys(dmsDetails).some(k => dmsDetails[k as keyof typeof dmsDetails]) ? dmsDetails : undefined,
      claimAmount,
    };
  } catch (error) {
    console.error('[claimDataMapper] Error mapping claim data:', error);
    return null;
  }
}

/**
 * Determine user's role in the request
 */
export function determineUserRole(apiRequest: any, currentUserId: string): RequestRole {
  try {
    // Check if user is the initiator
    if (apiRequest.initiatorId === currentUserId || 
        apiRequest.initiator?.userId === currentUserId ||
        apiRequest.requestedBy?.userId === currentUserId) {
      return 'INITIATOR';
    }

    // Check if user is a dealer (participant with DEALER type)
    const participants = apiRequest.participants || [];
    const dealerParticipant = participants.find((p: any) => 
      (p.userId === currentUserId || p.user?.userId === currentUserId) &&
      (p.participantType === 'DEALER' || p.type === 'DEALER')
    );
    if (dealerParticipant) {
      return 'DEALER';
    }

    // Check if user is a department lead (approver at level 3)
    const approvalLevels = apiRequest.approvalLevels || [];
    const deptLeadLevel = approvalLevels.find((level: any) => 
      level.levelNumber === 3 &&
      (level.approverId === currentUserId || level.approver?.userId === currentUserId)
    );
    if (deptLeadLevel) {
      return 'DEPARTMENT_LEAD';
    }

    // Check if user is an approver
    const approverLevel = approvalLevels.find((level: any) => 
      (level.approverId === currentUserId || level.approver?.userId === currentUserId) &&
      level.status === 'PENDING'
    );
    if (approverLevel) {
      return 'APPROVER';
    }

    // Default to spectator
    return 'SPECTATOR';
  } catch (error) {
    console.error('[claimDataMapper] Error determining user role:', error);
    return 'SPECTATOR';
  }
}

/**
 * Get role-based visibility settings
 */
export function getRoleBasedVisibility(role: RequestRole): RoleVisibility {
  switch (role) {
    case 'INITIATOR':
      return {
        showDealerInfo: true,
        showProposalDetails: true,
        showIODetails: true,
        showDMSDetails: true,
        showClaimAmount: true,
        canEditClaimAmount: false, // Can only edit in specific scenarios
      };

    case 'DEALER':
      return {
        showDealerInfo: true,
        showProposalDetails: true,
        showIODetails: false,
        showDMSDetails: false,
        showClaimAmount: true,
        canEditClaimAmount: false,
      };

    case 'DEPARTMENT_LEAD':
      return {
        showDealerInfo: true,
        showProposalDetails: true,
        showIODetails: true,
        showDMSDetails: true,
        showClaimAmount: true,
        canEditClaimAmount: false,
      };

    case 'APPROVER':
      return {
        showDealerInfo: true,
        showProposalDetails: true,
        showIODetails: true,
        showDMSDetails: true,
        showClaimAmount: true,
        canEditClaimAmount: false,
      };

    case 'SPECTATOR':
    default:
      return {
        showDealerInfo: false,
        showProposalDetails: false,
        showIODetails: false,
        showDMSDetails: false,
        showClaimAmount: false,
        canEditClaimAmount: false,
      };
  }
}

