/**
 * 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;
    defaultGstRate?: number;
    closedExpensesBreakdown?: Array<{
      description: string;
      amount: number;
      gstRate?: number;
      gstAmt?: number;
      cgstAmt?: number;
      sgstAmt?: number;
      igstAmt?: number;
      totalAmt?: number;
      hsnCode?: string;
    }>;
    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;
      gstRate?: number;
      gstAmt?: number;
      cgstAmt?: number;
      sgstAmt?: number;
      igstAmt?: number;
      totalAmt?: number;
      hsnCode?: string;
    }>;
    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;
    // PWC Fields
    irn?: string;
    ackNo?: string;
    ackDate?: string;
    signedInvoiceUrl?: string;
    taxBreakdown?: any;
    creditNoteWfmData?: any[];
  };

  // 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 || [];

    // Raw claim details processed

    // 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 || '';

    // Activity fields mapped

    // 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 || exp.item_description || '',
        amount: Number(exp.amount) || 0,
        gstRate: exp.gstRate ?? exp.gst_rate,
        gstAmt: exp.gstAmt ?? exp.gst_amt,
        cgstAmt: exp.cgstAmt ?? exp.cgst_amt,
        sgstAmt: exp.sgstAmt ?? exp.sgst_amt,
        igstAmt: exp.igstAmt ?? exp.igst_amt,
        totalAmt: exp.totalAmt ?? exp.total_amt,
        hsnCode: exp.hsnCode || exp.hsn_code || exp.hsnCd || exp.hsn_cd || ''
      }))
      : (completionDetails?.closedExpenses ||
        completionDetails?.closed_expenses ||
        completionDetails?.closedExpensesBreakdown ||
        []);

    const activityInfo = {
      activityName,
      activityType,
      defaultGstRate: claimDetails.defaultGstRate || 18,
      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 hasProposalData = Boolean(
      (proposalDetails && Object.keys(proposalDetails).length > 0) &&
      (
        (Array.isArray(proposalDetails.costItems || proposalDetails.cost_items) &&
          (proposalDetails.costItems || proposalDetails.cost_items).length > 0) ||
        (Array.isArray(proposalDetails.costBreakup || proposalDetails.cost_breakup) &&
          (proposalDetails.costBreakup || proposalDetails.cost_breakup).length > 0) ||
        proposalDetails.proposalDocumentUrl ||
        proposalDetails.proposal_document_url ||
        proposalDetails.totalEstimatedBudget ||
        proposalDetails.total_estimated_budget ||
        proposalDetails.expectedCompletionDate ||
        proposalDetails.expected_completion_date ||
        proposalDetails.submittedAt ||
        proposalDetails.submitted_at
      )
    );

    const proposal = hasProposalData ? {
      proposalDocumentUrl: proposalDetails.proposalDocumentUrl || proposalDetails.proposal_document_url,
      costBreakup: Array.isArray(proposalDetails.costItems || proposalDetails.cost_items)
        ? (proposalDetails.costItems || proposalDetails.cost_items).map((item: any) => ({
          description: item.description || item.itemDescription || item.item_description || '',
          amount: Number(item.amount) || 0,
          gstRate: Number(item.gstRate ?? item.gst_rate ?? 0),
          gstAmt: Number(item.gstAmt ?? item.gst_amt ?? 0),
          cgstAmt: Number(item.cgstAmt ?? item.cgst_amt ?? 0),
          sgstAmt: Number(item.sgstAmt ?? item.sgst_amt ?? 0),
          igstAmt: Number(item.igstAmt ?? item.igst_amt ?? 0),
          totalAmt: Number(item.totalAmt ?? item.total_amt ?? 0),
          hsnCode: item.hsnCode || item.hsn_code || ''
        }))
        : Array.isArray(proposalDetails.costBreakup || proposalDetails.cost_breakup)
          ? (proposalDetails.costBreakup || proposalDetails.cost_breakup).map((item: any) => ({
            description: item.description || item.itemDescription || item.item_description || '',
            amount: Number(item.amount) || 0,
            gstRate: item.gstRate ?? item.gst_rate,
            gstAmt: item.gstAmt ?? item.gst_amt,
            cgstAmt: item.cgstAmt ?? item.cgst_amt,
            sgstAmt: item.sgstAmt ?? item.sgst_amt,
            igstAmt: item.igstAmt ?? item.igst_amt,
            totalAmt: item.totalAmt ?? item.total_amt,
            hsnCode: item.hsnCode || item.hsn_code || ''
          }))
          : [],
      totalEstimatedBudget: proposalDetails.totalEstimatedBudget || proposalDetails.total_estimated_budget || 0,
      timelineMode: proposalDetails.timelineMode || proposalDetails.timeline_mode,
      expectedCompletionDate: expectedCompletionDate,
      timelineForClosure: expectedCompletionDate,
      expectedCompletionDays: proposalDetails.expectedCompletionDays || proposalDetails.expected_completion_days,
      dealerComments: proposalDetails.dealerComments || proposalDetails.dealer_comments,
      submittedAt: proposalDetails.submittedAt || proposalDetails.submitted_at || proposalDetails.submittedOn,
      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
    // Invoice could be top-level or nested in some backend responses
    const inv = apiRequest.invoice || apiRequest.claimInvoice || apiRequest.claim_invoice || 
                apiRequest.claimRequest?.invoice || apiRequest.request?.invoice || invoice || {};
    const claimDetailsObj = claimDetails || {};

    const dmsDetails = {
      eInvoiceNumber: inv.invoiceNumber || inv.invoice_number || 
        claimDetailsObj.eInvoiceNumber || claimDetailsObj.e_invoice_number ||
        inv.dmsNumber || inv.dms_number,
      eInvoiceDate: inv.invoiceDate || inv.invoice_date || 
        claimDetailsObj.eInvoiceDate || claimDetailsObj.e_invoice_date,
      dmsNumber: inv.dmsNumber || inv.dms_number || 
        claimDetailsObj.dmsNumber || claimDetailsObj.dms_number,
      creditNoteNumber: creditNote.creditNoteNumber || creditNote.credit_note_number ||
        claimDetailsObj.creditNoteNumber || claimDetailsObj.credit_note_number,
      creditNoteDate: creditNote.creditNoteDate || creditNote.credit_note_date ||
        claimDetailsObj.creditNoteDate || claimDetailsObj.credit_note_date,
      creditNoteAmount:
        creditNote.creditNoteAmount !== undefined && creditNote.creditNoteAmount !== null
          ? Number(creditNote.creditNoteAmount)
          : (creditNote.credit_note_amount !== undefined && creditNote.credit_note_amount !== null
            ? Number(creditNote.credit_note_amount)
            : (claimDetailsObj.creditNoteAmount !== undefined && claimDetailsObj.creditNoteAmount !== null
              ? Number(claimDetailsObj.creditNoteAmount)
              : (claimDetailsObj.credit_note_amount !== undefined && claimDetailsObj.credit_note_amount !== null
                ? Number(claimDetailsObj.credit_note_amount)
                : undefined))),
      // PWC fields
      irn: inv.irn || claimDetailsObj.irn,
      ackNo: inv.ackNo || inv.ack_no || claimDetailsObj.ackNo || claimDetailsObj.ack_no,
      ackDate: inv.ackDate || inv.ack_date || claimDetailsObj.ackDate || claimDetailsObj.ack_date,
      signedInvoiceUrl: inv.signedInvoiceUrl || inv.signed_invoice_url || claimDetailsObj.signedInvoiceUrl || claimDetailsObj.signed_invoice_url,
      taxBreakdown: inv.taxBreakdown || claimDetailsObj.taxBreakdown,
      creditNoteWfmData: (apiRequest.creditNote?.items || apiRequest.creditNoteWfmData || claimDetails.creditNoteWfmData || []).map((item: any) => ({
        ...item,
        DOC_NO: item.creditNoteNumber || apiRequest.creditNote?.creditNoteNumber || item.DOC_NO,
        TRNS_UNIQ_NO: item.transactionNo || item.TRNS_UNIQ_NO,
        MESSAGE: item.description || item.MESSAGE,
        TDS_AMT: item.tdsAmount || item.TDS_AMT,
        CREDITED_TOTAL_AMT: item.creditAmount || item.amount || item.CREDITED_TOTAL_AMT,
      })),
    };

    // 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 {
    const normalize = (v: any) => (v || '').toString().trim().toLowerCase();
    const participants = Array.isArray(apiRequest.participants) ? apiRequest.participants : [];
    const currentParticipant = participants.find((p: any) =>
      (p.userId === currentUserId || p.user_id === currentUserId || p.user?.userId === currentUserId)
    );
    const currentUserEmail = normalize(
      currentParticipant?.userEmail ||
      currentParticipant?.user_email ||
      currentParticipant?.email ||
      currentParticipant?.user?.email ||
      (apiRequest.initiatorId === currentUserId ? apiRequest.initiator?.email : '')
    );
    const dealerEmail = normalize(
      apiRequest?.claimDetails?.dealerEmail ||
      apiRequest?.claimDetails?.dealer_email ||
      apiRequest?.dealerEmail ||
      apiRequest?.dealer?.email
    );

    // Dealer detection first: if current user's email matches dealer email, treat as DEALER.
    if (dealerEmail && currentUserEmail && currentUserEmail === dealerEmail) {
      return 'DEALER';
    }

    // Check if user is the initiator
    if (apiRequest.initiatorId === currentUserId ||
      apiRequest.initiator_id === currentUserId ||
      apiRequest.initiator?.userId === currentUserId ||
      apiRequest.initiator?.user_id === currentUserId ||
      apiRequest.requestedBy?.userId === currentUserId) {
      return 'INITIATOR';
    }

    // Check if user is a dealer (participant with DEALER type)
    const dealerParticipant = participants.find((p: any) =>
      (p.userId === currentUserId || p.user_id === currentUserId || p.user?.userId === currentUserId || p.user?.user_id === currentUserId) &&
      ((p.participantType || p.participant_type || p.type || '').toString().toUpperCase() === '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: true,
        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: true,
        showProposalDetails: true,
        showIODetails: false,
        showDMSDetails: true,
        showClaimAmount: false,
        canEditClaimAmount: false,
      };
  }
}

