'use client';

import { useEffect, useMemo, useState } from 'react';
import { Download } from 'lucide-react';
import { Modal } from '@/components/ui/modal';
import { useOrganization } from '@/context/OrganizationContext';
import { useAuth } from '@/hooks/auth/useAuth';
import { useSession } from '@/modules/sessionModule/detail/hooks/useSession';
import type { Organization } from '@/types/organization/organization';
import type { Session, CostBreakdown } from '@/types/session/session';
import type { ChargePoint } from '@/types/chargepoint/chargepoint';
import type { ChargePointLocation } from '@/types/chargepoint/chargepoint-location';
import {
  formatBreakdownType,
  resolveBreakdownLabel,
} from '@/modules/sessionModule/detail/utils/costBreakdown';
import { isSessionIdleOngoing } from '@/modules/sessionModule/detail/sessionDetailUtils';

type SessionReceiptOverlayProps = {
  readonly session: Session;
  readonly chargepoint: ChargePoint | null;
  readonly location: ChargePointLocation | null;
  readonly tenantDisplayName?: string | null;
};

const formatDateTime = (dateInput?: string | null): string => {
  if (!dateInput) return '-';
  const date = new Date(dateInput);
  if (Number.isNaN(date.getTime())) return '-';
  return date.toLocaleString('en-US', {
    day: '2-digit',
    month: 'short',
    year: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
    hour12: false,
  });
};

const formatDuration = (startInput?: string | null, endInput?: string | null): string => {
  if (!startInput || !endInput) return '-';
  const start = new Date(startInput);
  const end = new Date(endInput);
  if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) return '-';

  const totalSec = Math.max(0, Math.floor((end.getTime() - start.getTime()) / 1000));
  const hours = Math.floor(totalSec / 3600);
  const minutes = Math.floor((totalSec % 3600) / 60);
  const seconds = totalSec % 60;

  if (hours > 0) return `${hours}h ${minutes}m ${seconds}s`;
  if (minutes > 0) return `${minutes}m ${seconds}s`;
  return `${seconds}s`;
};

const formatCurrency = (amount: number, currency = 'IDR'): string => {
  try {
    return new Intl.NumberFormat('id-ID', {
      style: 'currency',
      currency,
      maximumFractionDigits: 0,
    }).format(Math.round(amount));
  } catch {
    return `${currency} ${Math.round(amount).toLocaleString('id-ID')}`;
  }
};

const formatQuantity = (item: CostBreakdown): string => {
  const qty = Number.isFinite(item.quantity) ? item.quantity : 0;
  return `${qty.toLocaleString('id-ID')} ${item.unit || ''}`.trim();
};

const isFlatFee = (item: CostBreakdown): boolean =>
  String(item.type || '').toUpperCase() === 'FLAT';

const formatUnitPrice = (item: CostBreakdown, currency = 'IDR'): string => {
  const unitPrice = Number.isFinite(item.unit_price) ? item.unit_price : 0;
  if (isFlatFee(item)) return `Max ${formatCurrency(unitPrice, currency)} total`;

  const unit = item.unit || 'unit';
  return `${formatCurrency(unitPrice, currency)}/${unit}`;
};

const formatBreakdownLabel = (item: CostBreakdown, index: number, session: Session): string => {
  const label = resolveBreakdownLabel(item, '', {
    rateFees: session.fee_details?.rate_fees,
    breakdown: session.cost?.breakdown,
    index,
  });
  const typeLabel = formatBreakdownType(item.type, '');

  if (!label && !typeLabel) return '-';
  if (!label) return typeLabel;
  if (!typeLabel) return label;
  if (label.toLowerCase() === typeLabel.toLowerCase()) return label;

  return `${label} (${typeLabel})`;
};

const getFeePlanName = (session: Session): string => {
  const feeName =
    typeof session.fee_details?.name === 'string' ? session.fee_details.name.trim() : '';
  if (feeName) return feeName;
  const legacyRate = typeof session.rate === 'string' ? session.rate.trim() : '';
  if (legacyRate) return legacyRate;
  const feeId = typeof session.fee === 'string' ? session.fee.trim() : '';
  return feeId || '-';
};

const renderDetailRow = (label: string, value: string) => (
  <div className="flex items-start justify-between gap-4 py-2">
    <dt className="text-sm text-gray-600 dark:text-gray-300">{label}</dt>
    <dd className="text-sm font-medium text-gray-900 dark:text-white text-right">{value}</dd>
  </div>
);

const getOperatorContact = (
  organization: Organization | null,
  location: ChargePointLocation | null,
  chargepoint: ChargePoint | null,
) => {
  const rawMeta = chargepoint?.meta_data as Record<string, unknown> | undefined;
  const metaOperator = (rawMeta?.operator as Record<string, unknown> | undefined) || undefined;

  const email =
    organization?.email ||
    (typeof rawMeta?.operator_email === 'string' ? rawMeta.operator_email : undefined) ||
    (typeof metaOperator?.email === 'string' ? metaOperator.email : undefined) ||
    '-';

  const phone =
    organization?.phone ||
    location?.phone ||
    (typeof rawMeta?.operator_phone === 'string' ? rawMeta.operator_phone : undefined) ||
    (typeof metaOperator?.phone === 'string' ? metaOperator.phone : undefined) ||
    '-';

  return { email, phone };
};

const loadImageAsDataUrl = async (url: string): Promise<string | null> => {
  try {
    const response = await fetch(url);
    if (!response.ok) return null;

    const blob = await response.blob();
    return await new Promise<string | null>((resolve) => {
      const reader = new FileReader();
      reader.onloadend = () => resolve(typeof reader.result === 'string' ? reader.result : null);
      reader.onerror = () => resolve(null);
      reader.readAsDataURL(blob);
    });
  } catch {
    return null;
  }
};

const formatOrgCodeDisplay = (code?: string | null): string | null => {
  if (!code) return null;
  const normalized = code.trim().replace(/[_-]+/g, ' ').toLowerCase();
  const withPlusSpacing = normalized.replace(/([a-z])plus$/i, '$1 plus');
  return withPlusSpacing
    .split(' ')
    .filter(Boolean)
    .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
    .join(' ');
};

export default function SessionReceiptOverlay({
  session,
  chargepoint,
  location,
  tenantDisplayName,
}: SessionReceiptOverlayProps) {
  const [isOpen, setIsOpen] = useState(false);
  const { organization } = useOrganization();
  const [tenantLogoUrl, setTenantLogoUrl] = useState<string | null>(null);
  useEffect(() => {
    const frame = requestAnimationFrame(() => {
      const element = document.getElementById('dynamic-branding-logo');
      setTenantLogoUrl(element?.getAttribute('data-logo') || null);
    });
    return () => cancelAnimationFrame(frame);
  }, []);
  const { state } = useAuth();
  const currentUser = state.user;
  const { session: liveSession, mutate: refreshSession } = useSession(session._id, session);
  const receiptSession = liveSession ?? session;
  const canDownloadReceipt =
    receiptSession.status === 'Ended' || receiptSession.status === 'Cancelled';

  const chargingStart = receiptSession.metrics?.charging_start || receiptSession.created_at;
  const chargingStop =
    receiptSession.metrics?.charging_stop ||
    (receiptSession.status === 'Ended' || receiptSession.status === 'Cancelled'
      ? receiptSession.updated_at
      : null);
  const timezone = useMemo(() => {
    const rawTimezone = receiptSession.metrics?.timezone?.trim();
    if (rawTimezone) return rawTimezone;
    try {
      return Intl.DateTimeFormat().resolvedOptions().timeZone || 'Local Device Time';
    } catch {
      return 'Local Device Time';
    }
  }, [receiptSession.metrics?.timezone]);
  const energyKwh = ((receiptSession.metrics?.energy_consumed || 0) / 1000).toFixed(2);
  const totalCost = receiptSession.cost?.amount || 0;
  const currency = receiptSession.cost?.currency || 'IDR';
  const feePlanName = getFeePlanName(receiptSession);
  const generatedAt = new Date().toISOString();
  const stationName = chargepoint?.name || receiptSession.chargepoint_name || '-';
  const locationAddress = receiptSession.location_name?.trim() || '-';
  const connectorName =
    typeof receiptSession.connector_number === 'number'
      ? `No. ${receiptSession.connector_number}`
      : '-';
  const sessionMeta =
    (receiptSession.meta_data as Record<string, unknown> | undefined) || undefined;
  const sessionUserFullName =
    typeof receiptSession.user_fullname === 'string' ? receiptSession.user_fullname.trim() : '';
  const currentUserFullName =
    `${currentUser?.firstname || ''} ${currentUser?.lastname || ''}`.trim();
  const customerName =
    (typeof sessionMeta?.customer_name === 'string' ? sessionMeta.customer_name : undefined) ||
    (typeof sessionMeta?.user_name === 'string' ? sessionMeta.user_name : undefined) ||
    (typeof sessionMeta?.full_name === 'string' ? sessionMeta.full_name : undefined) ||
    sessionUserFullName ||
    currentUserFullName ||
    '-';
  const customerEmail =
    (typeof sessionMeta?.customer_email === 'string' ? sessionMeta.customer_email : undefined) ||
    (typeof sessionMeta?.user_email === 'string' ? sessionMeta.user_email : undefined) ||
    (typeof sessionMeta?.email === 'string' ? sessionMeta.email : undefined) ||
    currentUser?.email ||
    '-';
  const customerPhone =
    (typeof sessionMeta?.customer_phone === 'string' ? sessionMeta.customer_phone : undefined) ||
    (typeof sessionMeta?.user_phone === 'string' ? sessionMeta.user_phone : undefined) ||
    (typeof sessionMeta?.phone === 'string' ? sessionMeta.phone : undefined) ||
    currentUser?.phone ||
    '-';
  const operatorContact = getOperatorContact(organization, location, chargepoint);
  const operatorCode =
    organization?.code ||
    chargepoint?.organization_code ||
    location?.organization_code ||
    'unknown-operator';
  const operatorCodeDisplay = operatorCode.replace(/_/g, ' ').replace(/\s+/g, ' ').trim();
  const organizationDisplayFromCode = formatOrgCodeDisplay(organization?.code);
  const organizationName =
    tenantDisplayName?.trim() ||
    organizationDisplayFromCode ||
    organization?.name?.trim() ||
    operatorCodeDisplay;
  const organizationEmail = organization?.email || operatorContact.email;
  const organizationPhone = organization?.phone || operatorContact.phone;
  const organizationLogoUrl = tenantLogoUrl || '';
  const organizationInitials =
    organizationName
      .split(' ')
      .filter(Boolean)
      .slice(0, 2)
      .map((part) => part.charAt(0).toUpperCase())
      .join('') || 'ORG';
  const logoUrl =
    tenantLogoUrl ||
    chargepoint?.avatar_url ||
    location?.avatar_url ||
    '';

  const handleDownloadPdf = async () => {
    const latestSession = (await refreshSession()) ?? receiptSession;
    const canDownloadLatest =
      latestSession.status === 'Ended' || latestSession.status === 'Cancelled';

    if (!canDownloadLatest) {
      alert('Receipt hanya tersedia setelah session selesai.');
      return;
    }

    try {
      const [{ jsPDF }, { default: autoTable }] = await Promise.all([
        import('jspdf'),
        import('jspdf-autotable'),
      ]);

      const doc = new jsPDF({
        orientation: 'portrait',
        unit: 'pt',
        format: 'a4',
      });

      const pageWidth = doc.internal.pageSize.getWidth();
      const pageHeight = doc.internal.pageSize.getHeight();
      const margin = 40;
      const labelWidth = 140;
      const valueWidth = pageWidth - margin * 2 - labelWidth;
      let y = 54;
      const watermarkText = `${organizationName.toUpperCase()} RECEIPT`;
      const pdfChargingStart = latestSession.metrics?.charging_start || latestSession.created_at;
      const pdfChargingStop =
        latestSession.metrics?.charging_stop ||
        (latestSession.status === 'Ended' || latestSession.status === 'Cancelled'
          ? latestSession.updated_at
          : null);
      const pdfTimezone = latestSession.metrics?.timezone?.trim() || timezone;
      const pdfEnergyKwh = ((latestSession.metrics?.energy_consumed || 0) / 1000).toFixed(2);
      const pdfTotalCost = latestSession.cost?.amount || 0;
      const pdfCurrency = latestSession.cost?.currency || currency;
      const pdfFeePlanName = getFeePlanName(latestSession);
      const pdfLocationAddress = latestSession.location_name?.trim() || '-';
      const pdfConnectorName =
        typeof latestSession.connector_number === 'number'
          ? `No. ${latestSession.connector_number}`
          : '-';
      const latestSessionMeta =
        (latestSession.meta_data as Record<string, unknown> | undefined) || undefined;
      const pdfSessionUserFullName =
        typeof latestSession.user_fullname === 'string' ? latestSession.user_fullname.trim() : '';
      const pdfCustomerName =
        (typeof latestSessionMeta?.customer_name === 'string'
          ? latestSessionMeta.customer_name
          : undefined) ||
        (typeof latestSessionMeta?.user_name === 'string'
          ? latestSessionMeta.user_name
          : undefined) ||
        (typeof latestSessionMeta?.full_name === 'string'
          ? latestSessionMeta.full_name
          : undefined) ||
        pdfSessionUserFullName ||
        currentUserFullName ||
        '-';
      const pdfCustomerEmail =
        (typeof latestSessionMeta?.customer_email === 'string'
          ? latestSessionMeta.customer_email
          : undefined) ||
        (typeof latestSessionMeta?.user_email === 'string'
          ? latestSessionMeta.user_email
          : undefined) ||
        (typeof latestSessionMeta?.email === 'string' ? latestSessionMeta.email : undefined) ||
        currentUser?.email ||
        '-';
      const pdfCustomerPhone =
        (typeof latestSessionMeta?.customer_phone === 'string'
          ? latestSessionMeta.customer_phone
          : undefined) ||
        (typeof latestSessionMeta?.user_phone === 'string'
          ? latestSessionMeta.user_phone
          : undefined) ||
        (typeof latestSessionMeta?.phone === 'string' ? latestSessionMeta.phone : undefined) ||
        currentUser?.phone ||
        '-';

      // Faint centered watermark on first page
      doc.saveGraphicsState();
      doc.setTextColor(229, 231, 235);
      doc.setFont('helvetica', 'bold');
      doc.setFontSize(42);
      doc.text(watermarkText, pageWidth / 2, pageHeight / 2, {
        align: 'center',
        angle: 28,
      });
      doc.restoreGraphicsState();

      const nameY = y + 14;
      const emailY = y + 28;
      const phoneY = y + 42;
      const logoBoxX = margin;
      const logoBoxW = 104;
      const logoBoxH = 34;
      const logoBoxY = emailY - Math.floor(logoBoxH / 2) - 2;
      const identityStartX = logoBoxX + logoBoxW + 12;

      let hasRenderedLogo = false;
      const logoCandidates = [
        organization?.code
          ? `/api/organization/logo?w=640&h=240&org=${encodeURIComponent(organization.code)}`
          : '/api/organization/logo?w=640&h=240',
        organizationLogoUrl,
        organization?.code
          ? `/api/pwa/icon?size=256&org=${encodeURIComponent(organization.code)}`
          : '/api/pwa/icon?size=256',
      ].filter(Boolean);

      for (const logoCandidate of logoCandidates) {
        const logoDataUrl = await loadImageAsDataUrl(logoCandidate);
        if (!logoDataUrl) continue;
        try {
          const format =
            logoDataUrl.includes('image/jpeg') || logoDataUrl.includes('image/jpg')
              ? 'JPEG'
              : 'PNG';
          doc.addImage(
            logoDataUrl,
            format,
            logoBoxX,
            logoBoxY,
            logoBoxW,
            logoBoxH,
            undefined,
            'FAST',
          );
          hasRenderedLogo = true;
          break;
        } catch {
          // Try next candidate when current image format/source fails.
        }
      }

      if (!hasRenderedLogo) {
        // Fallback visual logo to keep header consistent even when org logo URL is missing/blocked.
        doc.setFillColor(243, 244, 246);
        doc.roundedRect(logoBoxX, logoBoxY, logoBoxW, logoBoxH, 6, 6, 'F');
        doc.setTextColor(55, 65, 81);
        doc.setFont('helvetica', 'bold');
        doc.setFontSize(12);
        doc.text(organizationInitials, logoBoxX + logoBoxW / 2, logoBoxY + 20, { align: 'center' });
      }

      doc.setFont('helvetica', 'bold');
      doc.setFontSize(12);
      doc.setTextColor(17, 24, 39);
      doc.text(organizationName, identityStartX, nameY);

      doc.setFont('helvetica', 'normal');
      doc.setFontSize(9);
      doc.setTextColor(75, 85, 99);
      doc.text(organizationEmail, identityStartX, emailY);
      doc.text(organizationPhone, identityStartX, phoneY);

      const headerContentBottomY = Math.max(logoBoxY + logoBoxH, phoneY);
      const headerSeparatorY = headerContentBottomY + 10;
      doc.setDrawColor(229, 231, 235);
      doc.setLineWidth(1);
      doc.line(margin, headerSeparatorY, pageWidth - margin, headerSeparatorY);
      y = headerSeparatorY + 24;

      const addTitle = (text: string) => {
        doc.setFont('helvetica', 'bold');
        doc.setFontSize(18);
        doc.setTextColor(17, 24, 39);
        doc.text(text, margin, y);
        y += 18;
      };

      const addSectionTitle = (text: string, topMargin = 12) => {
        y += topMargin;
        doc.setFont('helvetica', 'bold');
        doc.setFontSize(12);
        doc.setTextColor(17, 24, 39);
        doc.text(text, margin, y);
        y += 10;
      };

      const addRow = (label: string, value: string) => {
        const safeValue = value || '-';
        const valueLines = doc.splitTextToSize(safeValue, valueWidth);
        const rowHeight = Math.max(16, valueLines.length * 12 + 4);

        doc.setDrawColor(229, 231, 235);
        doc.line(margin, y, pageWidth - margin, y);

        doc.setFont('helvetica', 'normal');
        doc.setFontSize(10);
        doc.setTextColor(75, 85, 99);
        doc.text(label, margin, y + 12);

        doc.setFont('helvetica', 'bold');
        doc.setTextColor(17, 24, 39);
        doc.text(valueLines, margin + labelWidth, y + 12, { align: 'left' });

        y += rowHeight;
      };

      addTitle('Charging Session Receipt');

      addSectionTitle('Receipt Summary');
      addRow('Generated At', formatDateTime(generatedAt));
      addRow('Session ID', latestSession._id);
      addRow('Status', isSessionIdleOngoing(latestSession) ? 'IDLE ongoing' : latestSession.status);

      addSectionTitle('Station & Connector', 30);
      addRow('Station', stationName);
      addRow('Location', pdfLocationAddress);
      addRow('Connector', pdfConnectorName);

      addSectionTitle('Customer', 30);
      addRow('Name', pdfCustomerName);
      addRow('Email', pdfCustomerEmail);
      addRow('Phone', pdfCustomerPhone);

      addSectionTitle('Charging Metrics', 30);
      addRow('Charging Start', formatDateTime(pdfChargingStart));
      addRow('Charging Stop', formatDateTime(pdfChargingStop));
      addRow('Duration', formatDuration(pdfChargingStart, pdfChargingStop));
      addRow('Timezone', pdfTimezone);
      addRow('Energy Used', `${pdfEnergyKwh} kWh`);
      addRow('Fee Plan', pdfFeePlanName);
      addRow('Total Cost', formatCurrency(pdfTotalCost, pdfCurrency));

      if (latestSession.cost?.breakdown && latestSession.cost.breakdown.length > 0) {
        addSectionTitle('Cost Breakdown', 30);
        autoTable(doc, {
          startY: y + 4,
          margin: { left: margin, right: margin },
          head: [['Fee', 'Quantity', 'Unit Price', 'Amount']],
          body: latestSession.cost.breakdown.map((item, index) => [
            formatBreakdownLabel(item, index, latestSession),
            formatQuantity(item),
            formatUnitPrice(item, pdfCurrency),
            formatCurrency(item.total_cost, pdfCurrency),
          ]),
          styles: { fontSize: 9, textColor: [31, 41, 55], cellPadding: 6 },
          headStyles: { fillColor: [243, 244, 246], textColor: [55, 65, 81], fontStyle: 'bold' },
          columnStyles: {
            3: { halign: 'right' },
          },
          theme: 'grid',
        });
      }

      const datePart = new Date().toISOString().slice(0, 10);
      doc.save(`charging-receipt-${datePart}.pdf`);
    } catch (error) {
      console.error('Failed to generate receipt PDF:', error);
      alert('Failed to download PDF. Please try again.');
    }
  };

  return (
    <>
      <div className="w-full">
        <button
          type="button"
          onClick={async () => {
            await refreshSession();
            setIsOpen(true);
          }}
          disabled={!canDownloadReceipt}
          className="inline-flex w-full items-center justify-center gap-2 rounded-lg border-2 border-brand-600 bg-transparent px-4 py-3 text-base font-semibold text-brand-700 hover:bg-brand-50 disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-transparent dark:text-brand-400 dark:hover:bg-brand-900/20 dark:disabled:hover:bg-transparent"
        >
          <Download className="h-5 w-5" />
          Get Receipt
        </button>
        {!canDownloadReceipt && (
          <p className="mt-2 text-xs text-gray-500 dark:text-gray-400">
            Receipt can be downloaded after the session ends.
          </p>
        )}
      </div>

      <Modal
        isOpen={isOpen}
        onClose={() => setIsOpen(false)}
        className="mx-4 max-h-[90vh] max-w-3xl overflow-y-auto rounded-2xl border border-gray-200 p-6 sm:p-8 dark:border-gray-700"
      >
        <div className="relative mx-auto w-full max-w-2xl space-y-4 overflow-hidden">
          <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
            <p className="select-none text-center text-4xl font-extrabold tracking-widest text-gray-200/40 [transform:rotate(-22deg)] dark:text-white/5 sm:text-6xl">
              {organizationName.toUpperCase()}
            </p>
          </div>

          <header className="border-b border-gray-200 pb-3 dark:border-gray-700">
            <div className="mb-3 mt-3 flex items-start gap-3">
              {logoUrl && (
                <div className="shrink-0">
                  <img
                    src={logoUrl}
                    alt={`${organizationName} logo`}
                    className="h-10 w-28 object-contain object-left"
                    referrerPolicy="no-referrer"
                  />
                </div>
              )}
              <div className={`min-w-0 ${logoUrl ? 'pl-3' : ''}`}>
                <p className="text-sm font-semibold text-gray-900 dark:text-white">
                  {organizationName}
                </p>
                <p className="text-xs text-gray-600 dark:text-gray-300">{operatorContact.email}</p>
                <p className="text-xs text-gray-600 dark:text-gray-300">{operatorContact.phone}</p>
              </div>
            </div>
            <h2 className="text-xl font-bold text-gray-900 dark:text-white">
              Charging Session Receipt
            </h2>
          </header>

          <section className="rounded-lg border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-800">
            <h3 className="text-sm font-semibold text-gray-900 dark:text-white">Receipt Summary</h3>
            <dl className="mt-2 divide-y divide-gray-200 dark:divide-gray-700">
              {renderDetailRow('Generated At', formatDateTime(generatedAt))}
              {renderDetailRow('Session ID', receiptSession._id)}
              {renderDetailRow(
                'Status',
                isSessionIdleOngoing(receiptSession) ? 'IDLE ongoing' : receiptSession.status,
              )}
            </dl>
          </section>

          <section>
            <h3 className="text-sm font-semibold text-gray-900 dark:text-white">
              Station & Connector
            </h3>
            <dl className="mt-2 divide-y divide-gray-200 dark:divide-gray-700">
              {renderDetailRow('Station', stationName)}
              {renderDetailRow('Location', locationAddress)}
              {renderDetailRow('Connector', connectorName)}
            </dl>
          </section>

          <section>
            <h3 className="text-sm font-semibold text-gray-900 dark:text-white">Customer</h3>
            <dl className="mt-2 divide-y divide-gray-200 dark:divide-gray-700">
              {renderDetailRow('Name', customerName)}
              {renderDetailRow('Email', customerEmail)}
              {renderDetailRow('Phone', customerPhone)}
            </dl>
          </section>

          <section>
            <h3 className="text-sm font-semibold text-gray-900 dark:text-white">
              Charging Metrics
            </h3>
            <dl className="mt-2 divide-y divide-gray-200 dark:divide-gray-700">
              {renderDetailRow('Charging Start', formatDateTime(chargingStart))}
              {renderDetailRow('Charging Stop', formatDateTime(chargingStop))}
              {renderDetailRow('Duration', formatDuration(chargingStart, chargingStop))}
              {renderDetailRow('Timezone', timezone)}
              {renderDetailRow('Energy Used', `${energyKwh} kWh`)}
              {renderDetailRow('Fee Plan', feePlanName)}
              {renderDetailRow('Total Cost', formatCurrency(totalCost, currency))}
            </dl>
          </section>

          {receiptSession.cost?.breakdown && receiptSession.cost.breakdown.length > 0 && (
            <section>
              <h3 className="text-sm font-semibold text-gray-900 dark:text-white">
                Cost Breakdown
              </h3>
              <div className="mt-2 overflow-hidden rounded-lg border border-gray-200 dark:border-gray-700">
                <table className="w-full table-fixed text-left text-xs sm:text-sm">
                  <thead className="bg-gray-100 dark:bg-gray-800">
                    <tr>
                      <th className="w-1/2 px-3 py-2 font-semibold text-gray-700 dark:text-gray-200">
                        Fee
                      </th>
                      <th className="w-1/4 px-3 py-2 font-semibold text-gray-700 dark:text-gray-200">
                        Quantity
                      </th>
                      <th className="w-1/4 px-3 py-2 text-right font-semibold text-gray-700 dark:text-gray-200">
                        Amount
                      </th>
                    </tr>
                  </thead>
                  <tbody className="divide-y divide-gray-200 bg-white dark:divide-gray-700 dark:bg-gray-900">
                    {receiptSession.cost.breakdown.map((item, index) => (
                      <tr
                        key={`${item.type}-${item.fee_name ?? item.rate_name ?? 'no-name'}-${item.period?.start ?? 'no-start'}-${item.period?.end ?? 'no-end'}-${index}`}
                      >
                        <td className="px-3 py-2 text-gray-800 dark:text-gray-100">
                          <p className="font-medium text-gray-900 dark:text-white">
                            {formatBreakdownLabel(item, index, receiptSession)}
                          </p>
                          <p className="mt-0.5 text-xs font-normal text-gray-500 dark:text-gray-400">
                            {formatUnitPrice(item, currency)}
                          </p>
                        </td>
                        <td className="break-words px-3 py-2 text-gray-800 dark:text-gray-100">
                          {formatQuantity(item)}
                        </td>
                        <td className="px-3 py-2 text-right font-medium text-gray-900 dark:text-white">
                          {formatCurrency(item.total_cost, currency)}
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            </section>
          )}

          <div className="pt-2">
            <button
              type="button"
              onClick={handleDownloadPdf}
              disabled={!canDownloadReceipt}
              className="inline-flex w-full items-center justify-center gap-2 rounded-lg border-2 border-brand-600 bg-transparent px-4 py-3 text-base font-semibold text-brand-700 hover:bg-brand-50 disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-transparent dark:text-brand-400 dark:hover:bg-brand-900/20 dark:disabled:hover:bg-transparent"
            >
              <Download className="h-5 w-5" />
              Download PDF
            </button>
          </div>
        </div>
      </Modal>
    </>
  );
}
