import React, { useEffect, useMemo, useState } from 'react';
import {
  IonContent,
  IonIcon,
  IonPage,
  IonRefresher,
  IonRefresherContent,
  IonSegment,
  IonSegmentButton,
  IonSkeletonText,
  IonLabel,
  useIonViewWillEnter,
} from '@ionic/react';
import { fileTrayOutline } from 'ionicons/icons';
import momImage from '../assets/mom.jpg';
import dadImage from '../assets/dad.jpg';
import { useHistory } from 'react-router-dom';
import { supabase } from '../supabase';
import { useAuth } from '../contexts/AuthContext';
import ActivityListItem from '../components/ActivityListItem';
import { setStatusBarStyle, Style } from '../utils/statusBar';
import '../styles/activity.css';
import '../styles/recipients.css';

type RecipientRow = {
  id: string;
  first_name: string;
  last_name: string;
  photo_path: string | null;
};

type MerchantRow = {
  id: string;
  name: string;
  branch_name: string | null;
};

type OrderRow = {
  id: string;
  service_type: string;
  amount: number;
  status: string;
  created_at: string;
  recipient_id: string;
  merchant_id: string | null;
  recipients: RecipientRow | null;
  merchants: MerchantRow | null;
};

type VoucherRow = {
  id: string;
  order_id: string;
  status: string;
  redeemed_at: string | null;
  redeemed_merchant_id: string | null;
};

type RedemptionRow = {
  id: string;
  voucher_id: string;
  order_id: string;
  merchant_id: string;
  redeemed_at: string;
};

type ActivityMetadata = {
  statusText?: string;
  avatarLabel?: string;
  avatarTone?: string;
  avatarImage?: string;
  voucherId?: string;
};

type UnifiedActivityItem = {
  kind: 'voucher' | 'order';
  id: string;
  event_type: string;
  service_type: string;
  title: string;
  subtitle: string;
  amount: number | null;
  event_at: string;
  order_id: string;
  metadata: ActivityMetadata;
};

type ActivityTypeFilter =
  | 'all'
  | 'orders'
  | 'vouchers'
  | 'completed'
  | 'alerts';

type ActivityFilterRange = '7' | '30' | '90' | 'all';

type VoucherActivityStatus = 'created' | 'redeemed' | 'partially';

const previewUserId = '00000000-0000-0000-0000-000000000000';

const dayLabel = (dateText: string) => {
  const date = new Date(dateText);
  const today = new Date();
  const yesterday = new Date();
  yesterday.setDate(today.getDate() - 1);

  if (date.toDateString() === today.toDateString()) return 'Today';
  if (date.toDateString() === yesterday.toDateString()) return 'Yesterday';
  return date.toLocaleDateString(undefined, {
    month: 'short',
    day: 'numeric',
    year: 'numeric',
  });
};

const getMerchantDisplayName = (merchant?: MerchantRow | null) => {
  if (!merchant) return null;
  return `${merchant.name}${merchant.branch_name ? ` ${merchant.branch_name}` : ''}`;
};

const getRecipientDisplayName = (recipient?: RecipientRow | null) => {
  if (!recipient) return 'Loved one';
  return `${recipient.first_name} ${recipient.last_name}`.trim();
};

const getInitials = (name: string) =>
  name
    .split(' ')
    .map((part) => part.charAt(0))
    .join('')
    .slice(0, 2)
    .toUpperCase();

const getNormalizedServiceType = (value: string) => {
  const normalized = value.toLowerCase();
  if (normalized.includes('grocery')) return 'grocery';
  if (normalized.includes('medication') || normalized.includes('pharmacy')) {
    return 'medication';
  }
  if (normalized.includes('airtime') || normalized.includes('data')) {
    return 'airtime';
  }
  if (normalized.includes('electricity') || normalized.includes('zesa')) {
    return 'electricity';
  }
  return normalized;
};

const getNormalizedServiceLabel = (serviceType: string) => {
  const normalizedService = getNormalizedServiceType(serviceType);
  if (normalizedService === 'grocery') return 'Grocery voucher';
  if (normalizedService === 'medication') return 'Medication voucher';
  if (normalizedService === 'airtime') return 'Airtime & Data';
  if (normalizedService === 'electricity') return 'Electricity';
  return serviceType.charAt(0).toUpperCase() + serviceType.slice(1);
};

const isVoucherService = (serviceType: string) => {
  const normalizedService = getNormalizedServiceType(serviceType);
  return normalizedService === 'grocery' || normalizedService === 'medication';
};

const getVoucherStatus = (
  orderStatus: string,
  voucher?: VoucherRow,
  redemptions: RedemptionRow[] = []
): VoucherActivityStatus => {
  const combinedStatus = `${orderStatus} ${voucher?.status ?? ''}`
    .toLowerCase()
    .replace(/_/g, ' ');

  if (combinedStatus.includes('partial')) return 'partially';
  if (
    combinedStatus.includes('redeemed') ||
    Boolean(voucher?.redeemed_at) ||
    Boolean(voucher?.redeemed_merchant_id) ||
    redemptions.length > 0
  ) {
    return 'redeemed';
  }

  return 'created';
};

const getOrderStatus = (status: string) => {
  const normalizedStatus = status.toLowerCase().replace(/_/g, ' ');
  if (
    normalizedStatus.includes('completed') ||
    normalizedStatus.includes('delivered') ||
    normalizedStatus.includes('active')
  ) {
    return 'completed';
  }
  return 'created';
};

const getActivityStatusTone = (_serviceType: string, statusText?: string) => {
  const normalizedStatus = statusText?.toLowerCase() ?? '';

  if (normalizedStatus.includes('redeemed')) return 'success';
  if (normalizedStatus.includes('partial')) return 'partial';
  return 'warning';
};

const getSeededRecipientImage = (
  firstName?: string | null,
  photoPath?: string | null
) => {
  const normalizedPath = photoPath?.trim().toLowerCase();
  if (normalizedPath === 'mom.jpg' || normalizedPath === 'mum.jpg') {
    return momImage;
  }
  if (normalizedPath === 'dad.jpg' || normalizedPath === 'father.jpg') {
    return dadImage;
  }

  const normalizedName = firstName?.trim().toLowerCase();
  if (normalizedName === 'mum' || normalizedName === 'mom') return momImage;
  if (normalizedName === 'dad' || normalizedName === 'father') return dadImage;
  return undefined;
};

const getRecipientAvatarUrl = async (recipient?: RecipientRow | null) => {
  if (!recipient) return undefined;

  const seededImage = getSeededRecipientImage(
    recipient.first_name,
    recipient.photo_path
  );
  if (seededImage) return seededImage;

  if (!recipient.photo_path) return undefined;

  const { data } = await supabase.storage
    .from('recipient-photos')
    .createSignedUrl(recipient.photo_path, 3600);

  return data?.signedUrl;
};

const getAvatarTone = (serviceType: string) => {
  const normalizedService = getNormalizedServiceType(serviceType);
  if (normalizedService === 'medication') return 'mint';
  if (normalizedService === 'airtime') return 'sky';
  if (normalizedService === 'electricity') return 'gold';
  return 'lavender';
};

const ActivityPage: React.FC = () => {
  const history = useHistory();
  const { user } = useAuth();
  const [events, setEvents] = useState<UnifiedActivityItem[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [range, setRange] = useState<ActivityFilterRange>('all');
  const [typeFilter, setTypeFilter] = useState<ActivityTypeFilter>('all');

  useIonViewWillEnter(() => {
    setStatusBarStyle(Style.Light);
  });

  useEffect(() => {
    void loadActivity();
  }, [user?.id]);

  const showError = (message: string) => {
    setError(message);
    setTimeout(() => setError(null), 4000);
  };

  const fetchOrdersForUser = async (userId: string) => {
    return supabase
      .from('support_orders')
      .select(
        'id,service_type,amount,status,created_at,recipient_id,merchant_id,recipients(id,first_name,last_name,photo_path),merchants(id,name,branch_name)'
      )
      .eq('user_id', userId)
      .order('created_at', { ascending: false });
  };

  const loadActivity = async () => {
    setLoading(true);
    setError(null);

    const activeUserId = user?.id ?? previewUserId;
    let { data: ordersData, error: ordersError } =
      await fetchOrdersForUser(activeUserId);

    if (!ordersError && user?.id && (ordersData ?? []).length === 0) {
      const previewResult = await fetchOrdersForUser(previewUserId);
      ordersData = previewResult.data;
      ordersError = previewResult.error;
    }

    if (ordersError) {
      showError(ordersError.message || 'Failed to load activity');
      setEvents([]);
      setLoading(false);
      return;
    }

    const orders = (ordersData ?? []) as unknown as OrderRow[];
    const orderIds = orders.map((order) => order.id);
    const recipientIds = Array.from(
      new Set(orders.map((order) => order.recipient_id).filter(Boolean))
    );

    const [recipientsRes, vouchersRes, redemptionsRes, merchantsRes] =
      await Promise.all([
        recipientIds.length > 0
          ? supabase
              .from('recipients')
              .select('id,first_name,last_name,photo_path')
              .in('id', recipientIds)
          : Promise.resolve({ data: [], error: null }),
        orderIds.length > 0
          ? supabase
              .from('vouchers')
              .select('id,order_id,status,redeemed_at,redeemed_merchant_id')
              .in('order_id', orderIds)
          : Promise.resolve({ data: [], error: null }),
        orderIds.length > 0
          ? supabase
              .from('voucher_redemptions')
              .select('id,voucher_id,order_id,merchant_id,redeemed_at')
              .in('order_id', orderIds)
          : Promise.resolve({ data: [], error: null }),
        supabase.from('merchants').select('id,name,branch_name'),
      ]);

    if (
      recipientsRes.error ||
      vouchersRes.error ||
      redemptionsRes.error ||
      merchantsRes.error
    ) {
      showError(
        recipientsRes.error?.message ||
          vouchersRes.error?.message ||
          redemptionsRes.error?.message ||
          merchantsRes.error?.message ||
          'Failed to load activity details'
      );
      setEvents([]);
      setLoading(false);
      return;
    }

    const recipientsById = new Map(
      ((recipientsRes.data ?? []) as RecipientRow[]).map((recipient) => [
        recipient.id,
        recipient,
      ])
    );
    const vouchersByOrderId = new Map(
      ((vouchersRes.data ?? []) as VoucherRow[]).map((voucher) => [
        voucher.order_id,
        voucher,
      ])
    );
    const redemptionsByOrderId = (
      (redemptionsRes.data ?? []) as RedemptionRow[]
    ).reduce<Map<string, RedemptionRow[]>>((acc, redemption) => {
      const existing = acc.get(redemption.order_id) ?? [];
      existing.push(redemption);
      acc.set(redemption.order_id, existing);
      return acc;
    }, new Map());
    const merchantsById = new Map(
      ((merchantsRes.data ?? []) as MerchantRow[]).map((merchant) => [
        merchant.id,
        merchant,
      ])
    );

    const mappedRows = await Promise.all(
      orders.map(async (order) => {
        const recipient =
          order.recipients ?? recipientsById.get(order.recipient_id) ?? null;
        const recipientName = getRecipientDisplayName(recipient);
        const serviceType = getNormalizedServiceType(order.service_type);
        const voucher = vouchersByOrderId.get(order.id);
        const redemptions = redemptionsByOrderId.get(order.id) ?? [];
        const latestRedemption = [...redemptions].sort(
          (a, b) =>
            new Date(b.redeemed_at).getTime() -
            new Date(a.redeemed_at).getTime()
        )[0];
        const statusText = isVoucherService(serviceType)
          ? getVoucherStatus(order.status, voucher, redemptions)
          : getOrderStatus(order.status);
        const redemptionMerchant = latestRedemption?.merchant_id
          ? merchantsById.get(latestRedemption.merchant_id)
          : null;
        const voucherMerchant = voucher?.redeemed_merchant_id
          ? merchantsById.get(voucher.redeemed_merchant_id)
          : null;
        const orderMerchant =
          order.merchants ??
          (order.merchant_id ? merchantsById.get(order.merchant_id) : null);
        const merchantName =
          getMerchantDisplayName(redemptionMerchant) ??
          getMerchantDisplayName(voucherMerchant) ??
          getMerchantDisplayName(orderMerchant);
        const subtitle =
          isVoucherService(serviceType) &&
          (statusText === 'redeemed' || statusText === 'partially')
            ? (merchantName ?? 'Redemption merchant unavailable')
            : recipientName;
        const avatarImage = await getRecipientAvatarUrl(recipient);

        return {
          kind: isVoucherService(serviceType) ? 'voucher' : 'order',
          id: order.id,
          order_id: order.id,
          event_type: serviceType,
          service_type: serviceType,
          title: getNormalizedServiceLabel(serviceType),
          subtitle,
          amount: Number(order.amount ?? 0),
          event_at: order.created_at,
          metadata: {
            statusText,
            avatarLabel: getInitials(recipientName),
            avatarTone: getAvatarTone(serviceType),
            avatarImage,
            voucherId: voucher?.id,
          },
        } satisfies UnifiedActivityItem;
      })
    );

    setEvents(
      mappedRows.sort(
        (a, b) =>
          new Date(b.event_at).getTime() - new Date(a.event_at).getTime()
      )
    );
    setLoading(false);
  };

  const filteredEvents = useMemo(() => {
    const threshold = new Date();
    if (range !== 'all') {
      const days = Number(range);
      threshold.setHours(0, 0, 0, 0);
      threshold.setDate(threshold.getDate() - (days - 1));
    }

    return events.filter((item) => {
      if (
        range !== 'all' &&
        new Date(item.event_at).getTime() < threshold.getTime()
      ) {
        return false;
      }

      switch (typeFilter) {
        case 'all':
          return true;
        case 'orders':
          return item.kind === 'order';
        case 'vouchers':
          return item.kind === 'voucher';
        case 'completed': {
          const status = (item.metadata.statusText || '').toLowerCase();
          return (
            status.includes('completed') ||
            status.includes('redeemed') ||
            status.includes('partial')
          );
        }
        case 'alerts':
          return false;
        default:
          return true;
      }
    });
  }, [events, range, typeFilter]);

  const groups = useMemo(() => {
    return filteredEvents.reduce<Record<string, UnifiedActivityItem[]>>(
      (acc, event) => {
        const label = dayLabel(event.event_at);
        acc[label] = acc[label] ?? [];
        acc[label].push(event);
        return acc;
      },
      {}
    );
  }, [filteredEvents]);

  const handleRefresh = async (event: CustomEvent) => {
    await loadActivity();
    event.detail.complete();
  };

  const handleOpenEvent = (event: UnifiedActivityItem) => {
    history.push(`/orders/${event.order_id}`);
  };

  return (
    <IonPage style={{ backgroundColor: '#fafafa' }}>
      <IonContent
        fullscreen
        className="activity-shell"
        style={
          {
            '--background': 'linear-gradient(180deg, #fafafa 0%, #f4f0ff 100%)',
            '--padding-start': '0px',
            '--padding-end': '0px',
          } as React.CSSProperties
        }
      >
        <IonRefresher slot="fixed" onIonRefresh={handleRefresh}>
          <IonRefresherContent />
        </IonRefresher>

        <div
          className="activity-top-row"
          style={{ padding: 'calc(18px + var(--ion-safe-area-top)) 0 0' }}
        >
          <div className="activity-title-block">
            <h1 className="activity-page-title">Activity</h1>
            <p className="activity-page-subtitle">Orders & care timeline</p>
          </div>
        </div>

        <div className="activity-type-filter-row">
          {(
            [
              'all',
              'orders',
              'vouchers',
              'completed',
              'alerts',
            ] as ActivityTypeFilter[]
          ).map((type) => (
            <button
              key={type}
              type="button"
              className={`activity-type-chip ${typeFilter === type ? 'active' : ''}`}
              onClick={() => setTypeFilter(type)}
            >
              {type.charAt(0).toUpperCase() + type.slice(1)}
            </button>
          ))}
        </div>

        <div className="activity-filter-row">
          <div className="activity-range-shell">
            <IonSegment
              value={range}
              className="activity-range-segment"
              onIonChange={(event) =>
                setRange((event.detail.value as ActivityFilterRange) ?? '30')
              }
            >
              <IonSegmentButton value="all">
                <IonLabel>All</IonLabel>
              </IonSegmentButton>
              <IonSegmentButton value="30">
                <IonLabel>30 days</IonLabel>
              </IonSegmentButton>
              <IonSegmentButton value="90">
                <IonLabel>90 days</IonLabel>
              </IonSegmentButton>
            </IonSegment>
          </div>
        </div>

        {error && (
          <p style={{ margin: '0 20px 12px', color: '#dc2626', fontSize: 13 }}>
            {error}
          </p>
        )}

        {loading ? (
          <div className="activity-grouped-list">
            {[1, 2, 3].map((item) => (
              <div key={item} className="activity-list-item">
                <IonSkeletonText
                  animated
                  style={{
                    width: 40,
                    height: 40,
                    borderRadius: 12,
                    flexShrink: 0,
                  }}
                />
                <div style={{ flex: 1 }}>
                  <IonSkeletonText
                    animated
                    style={{ width: '70%', height: 15 }}
                  />
                  <IonSkeletonText
                    animated
                    style={{ width: '45%', height: 12 }}
                  />
                </div>
              </div>
            ))}
          </div>
        ) : filteredEvents.length === 0 ? (
          <div className="empty-state-card">
            <IonIcon icon={fileTrayOutline} className="esc-icon" />
            <h2 className="esc-title">
              {typeFilter === 'all'
                ? 'No activity in this range'
                : 'No matching activity'}
            </h2>
            <p className="esc-msg">
              Try a longer date range or switch the activity filter.
            </p>
          </div>
        ) : (
          Object.entries(groups).map(([label, items]) => (
            <div key={label}>
              <p className="activity-date-group-label">{label}</p>
              <div className="activity-grouped-list">
                {items.map((item) => (
                  <ActivityListItem
                    key={item.id}
                    id={item.id}
                    eventType={item.event_type}
                    title={item.title}
                    subtitle={item.subtitle}
                    amount={item.amount ?? undefined}
                    statusText={item.metadata.statusText}
                    statusTone={getActivityStatusTone(
                      item.event_type,
                      item.metadata.statusText
                    )}
                    avatarLabel={item.metadata.avatarLabel}
                    avatarTone={item.metadata.avatarTone}
                    avatarImage={item.metadata.avatarImage}
                    onClick={() => handleOpenEvent(item)}
                    onStatusClick={() => handleOpenEvent(item)}
                  />
                ))}
              </div>
            </div>
          ))
        )}
      </IonContent>
    </IonPage>
  );
};

export default ActivityPage;
