import { Ionicons } from '@expo/vector-icons';
import dayjs from 'dayjs';
import { LinearGradient } from 'expo-linear-gradient';
import { Stack, useRouter } from 'expo-router';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import {
  DimensionValue,
  FlatList,
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
} from 'react-native';

import { Colors } from '@/constants/Colors';
import {
  CycleRecord,
  DEFAULT_PERIOD_LENGTH,
  MenstrualDayCell,
  MenstrualDayStatus,
  MenstrualTimeline,
  buildMenstrualTimeline
} from '@/utils/menstrualCycle';

type TabKey = 'cycle' | 'analysis';

const ITEM_HEIGHT = 380;
const STATUS_COLORS: Record<MenstrualDayStatus, { bg: string; text: string }> = {
  period: { bg: '#f5679f', text: '#fff' },
  'predicted-period': { bg: '#f8d9e9', text: '#9b2c6a' },
  fertile: { bg: '#d9d2ff', text: '#5a52c5' },
  'ovulation-day': { bg: '#5b4ee4', text: '#fff' },
};

const WEEK_LABELS = ['一', '二', '三', '四', '五', '六', '日'];

const chunkArray = <T,>(array: T[], size: number): T[][] => {
  const result: T[][] = [];
  for (let i = 0; i < array.length; i += size) {
    result.push(array.slice(i, i + size));
  }
  return result;
};

const DayCell = ({
  cell,
  isSelected,
  onPress,
}: {
  cell: Extract<MenstrualDayCell, { type: 'day' }>;
  isSelected: boolean;
  onPress: () => void;
}) => {
  const status = cell.info?.status;
  const colors = status ? STATUS_COLORS[status] : undefined;

  return (
    <TouchableOpacity
      activeOpacity={0.8}
      style={styles.dayCell}
      onPress={onPress}
    >
      <View
        style={[
          styles.dayCircle,
          colors && { backgroundColor: colors.bg },
          isSelected && styles.dayCircleSelected,
          cell.isToday && styles.todayOutline,
        ]}
      >
        <Text
          style={[
            styles.dayLabel,
            colors && { color: colors.text },
            !colors && styles.dayLabelDefault,
          ]}
        >
          {cell.label}
        </Text>
      </View>
      {cell.isToday && <Text style={styles.todayText}>今天</Text>}
    </TouchableOpacity>
  );
};

const MonthBlock = ({
  month,
  selectedDateKey,
  onSelect,
  renderTip,
}: {
  month: MenstrualTimeline['months'][number];
  selectedDateKey: string;
  onSelect: (dateKey: string) => void;
  renderTip: (colIndex: number) => React.ReactNode;
}) => {
  const weeks = useMemo(() => chunkArray(month.cells, 7), [month.cells]);

  return (
    <View style={styles.monthCard}>
      <View style={styles.monthHeader}>
        <Text style={styles.monthTitle}>{month.title}</Text>
        <Text style={styles.monthSubtitle}>{month.subtitle}</Text>
      </View>
      <View style={styles.weekRow}>
        {WEEK_LABELS.map((label) => (
          <Text key={label} style={styles.weekLabel}>
            {label}
          </Text>
        ))}
      </View>
      <View style={styles.monthGrid}>
        {weeks.map((week, weekIndex) => {
          const selectedIndex = week.findIndex(
            (c) => c.type === 'day' && c.date.format('YYYY-MM-DD') === selectedDateKey
          );

          return (
            <React.Fragment key={weekIndex}>
              <View style={styles.daysRow}>
                {week.map((cell) => {
                  if (cell.type === 'placeholder') {
                    return <View key={cell.key} style={styles.dayCell} />;
                  }
                  const dateKey = cell.date.format('YYYY-MM-DD');
                  return (
                    <DayCell
                      key={cell.key}
                      cell={cell}
                      isSelected={selectedDateKey === dateKey}
                      onPress={() => onSelect(dateKey)}
                    />
                  );
                })}
              </View>
              {selectedIndex !== -1 && (
                <View style={styles.inlineTipContainer}>
                  {renderTip(selectedIndex)}
                </View>
              )}
            </React.Fragment>
          );
        })}
      </View>
    </View>
  );
};

export default function MenstrualCycleScreen() {
  const router = useRouter();
  const [records, setRecords] = useState<CycleRecord[]>([]);
  const [windowConfig, setWindowConfig] = useState({ before: 2, after: 3 });
  const timeline = useMemo(
    () =>
      buildMenstrualTimeline({
        monthsBefore: windowConfig.before,
        monthsAfter: windowConfig.after,
        records,
        defaultPeriodLength: DEFAULT_PERIOD_LENGTH,
      }),
    [records, windowConfig]
  );
  const [activeTab, setActiveTab] = useState<TabKey>('cycle');
  const [selectedDateKey, setSelectedDateKey] = useState(
    dayjs().format('YYYY-MM-DD')
  );
  const listRef = useRef<FlatList>(null);
  const offsetRef = useRef(0);
  const prependDeltaRef = useRef(0);
  const loadingPrevRef = useRef(false);

  const selectedInfo = timeline.dayMap[selectedDateKey];
  const selectedDate = dayjs(selectedDateKey);

 
  const handleMarkStart = () => {
    if (selectedDate.isAfter(dayjs(), 'day')) return;

    // Check if the selected date is already covered by an existing record (including duration)
    const isCovered = records.some((r) => {
      const start = dayjs(r.startDate);
      const end = start.add((r.periodLength ?? DEFAULT_PERIOD_LENGTH) - 1, 'day');
      return (
        (selectedDate.isSame(start, 'day') || selectedDate.isAfter(start, 'day')) &&
        (selectedDate.isSame(end, 'day') || selectedDate.isBefore(end, 'day'))
      );
    });
    if (isCovered) return;

    setRecords((prev) => {
      const updated = [...prev];
      
      // 1. Check if selectedDate is immediately after an existing period
      const prevRecordIndex = updated.findIndex((r) => {
        const start = dayjs(r.startDate);
        const end = start.add((r.periodLength ?? DEFAULT_PERIOD_LENGTH) - 1, 'day');
        return end.add(1, 'day').isSame(selectedDate, 'day');
      });

      // 2. Check if selectedDate is immediately before an existing period
      const nextRecordIndex = updated.findIndex((r) => {
        return dayjs(r.startDate).subtract(1, 'day').isSame(selectedDate, 'day');
      });

      if (prevRecordIndex !== -1 && nextRecordIndex !== -1) {
        // Merge three parts: Prev + Selected + Next
        const prevRecord = updated[prevRecordIndex];
        const nextRecord = updated[nextRecordIndex];
        const newLength =
          (prevRecord.periodLength ?? DEFAULT_PERIOD_LENGTH) +
          1 +
          (nextRecord.periodLength ?? DEFAULT_PERIOD_LENGTH);

        updated[prevRecordIndex] = {
          ...prevRecord,
          periodLength: newLength,
        };
        // Remove the next record since it's merged
        updated.splice(nextRecordIndex, 1);
      } else if (prevRecordIndex !== -1) {
        // Extend previous record
        const prevRecord = updated[prevRecordIndex];
        updated[prevRecordIndex] = {
          ...prevRecord,
          periodLength: (prevRecord.periodLength ?? DEFAULT_PERIOD_LENGTH) + 1,
        };
      } else if (nextRecordIndex !== -1) {
        // Extend next record (start earlier)
        const nextRecord = updated[nextRecordIndex];
        updated[nextRecordIndex] = {
          ...nextRecord,
          startDate: selectedDate.format('YYYY-MM-DD'),
          periodLength: (nextRecord.periodLength ?? DEFAULT_PERIOD_LENGTH) + 1,
        };
      } else {
        // Create new isolated record
        const newRecord: CycleRecord = {
          startDate: selectedDate.format('YYYY-MM-DD'),
          periodLength: 7,
          source: 'manual',
        };
        updated.push(newRecord);
      }

      return updated.sort(
        (a, b) => dayjs(a.startDate).valueOf() - dayjs(b.startDate).valueOf()
      );
    });
  };

  const handleCancelMark = () => {
    if (!selectedInfo || !selectedInfo.confirmed) return;
    if (selectedDate.isAfter(dayjs(), 'day')) return;
    const target = selectedDate;

    setRecords((prev) => {
      const updated: CycleRecord[] = [];
      prev.forEach((record) => {
        const start = dayjs(record.startDate);
        const periodLength = record.periodLength ?? DEFAULT_PERIOD_LENGTH;
        const diff = target.diff(start, 'day');

        if (diff < 0 || diff >= periodLength) {
          updated.push(record);
          return;
        }

        if (diff === 0) {
          // 取消开始日：移除整段记录
          return;
        }

        // diff > 0 且在区间内：将该日标记为结束日 (选中当日也被取消，所以长度为 diff)
        updated.push({
          ...record,
          periodLength: diff,
        });
      });

      return updated;
    });
  };

  const handleLoadPrevious = () => {
    if (loadingPrevRef.current) return;
    loadingPrevRef.current = true;
    const delta = 3;
    prependDeltaRef.current = delta;
    setWindowConfig((prev) => ({ ...prev, before: prev.before + delta }));
  };

  useEffect(() => {
    if (prependDeltaRef.current > 0 && listRef.current) {
      const offset = offsetRef.current + prependDeltaRef.current * ITEM_HEIGHT;
      requestAnimationFrame(() => {
        listRef.current?.scrollToOffset({ offset, animated: false });
        prependDeltaRef.current = 0;
        loadingPrevRef.current = false;
      });
    }
  }, [timeline.months.length]);

  const viewabilityConfig = useRef({
    viewAreaCoveragePercentThreshold: 10,
  }).current;

  const onViewableItemsChanged = useRef(({ viewableItems }: any) => {
    const minIndex = viewableItems.reduce(
      (acc: number, cur: any) => Math.min(acc, cur.index ?? acc),
      Number.MAX_SAFE_INTEGER
    );
    if (minIndex <= 1) {
      handleLoadPrevious();
    }
  }).current;

  const renderLegend = () => (
    <View style={styles.legendRow}>
      {[
        { label: '经期', key: 'period' as const },
        { label: '预测经期', key: 'predicted-period' as const },
        { label: '排卵期', key: 'fertile' as const },
        { label: '排卵日', key: 'ovulation-day' as const },
      ].map((item) => (
        <View key={item.key} style={styles.legendItem}>
          <View
            style={[
              styles.legendDot,
              { backgroundColor: STATUS_COLORS[item.key].bg },
              item.key === 'ovulation-day' && styles.legendDotRing,
            ]}
          />
          <Text style={styles.legendLabel}>{item.label}</Text>
        </View>
      ))}
    </View>
  );

  const listData = useMemo(() => {
    return timeline.months.map((m) => ({
      type: 'month' as const,
      id: m.id,
      month: m,
    }));
  }, [timeline.months]);

  const renderInlineTip = (columnIndex: number) => {
    // 14.28% per cell. Center is 7.14%.
    const pointerLeft = `${columnIndex * 14.2857 + 7.1428}%` as DimensionValue;
    const isFuture = selectedDate.isAfter(dayjs(), 'day');

    const base = (
      <View style={styles.inlineTipCard}>
        <View style={[styles.inlineTipPointer, { left: pointerLeft }]} />
        <View style={styles.inlineTipRow}>
          <View style={styles.inlineTipDate}>
            <Ionicons name="calendar-outline" size={16} color="#111827" />
            <Text style={styles.inlineTipDateText}>{selectedDate.format('M月D日')}</Text>
          </View>
          {!isFuture && (!selectedInfo || !selectedInfo.confirmed) && (
            <TouchableOpacity style={styles.inlinePrimaryBtn} onPress={handleMarkStart}>
              <Ionicons name="add" size={14} color="#fff" />
              <Text style={styles.inlinePrimaryText}>标记经期</Text>
            </TouchableOpacity>
          )}
          {!isFuture && selectedInfo?.confirmed && selectedInfo.status === 'period' && (
            <TouchableOpacity style={styles.inlineSecondaryBtn} onPress={handleCancelMark}>
              <Text style={styles.inlineSecondaryText}>取消标记</Text>
            </TouchableOpacity>
          )}
        </View>
      </View>
    );

    return base;
  };

  const renderCycleTab = () => (
    <View style={styles.tabContent}>
      {renderLegend()}


      <FlatList
        ref={listRef}
        data={listData}
        keyExtractor={(item) => item.id}
        renderItem={({ item }) => (
          <MonthBlock
            month={item.month}
            selectedDateKey={selectedDateKey}
            onSelect={(key) => setSelectedDateKey(key)}
            renderTip={renderInlineTip}
          />
        )}
        showsVerticalScrollIndicator={false}
        initialNumToRender={3}
        windowSize={5}
        maxToRenderPerBatch={4}
        removeClippedSubviews
        contentContainerStyle={styles.listContent}
        viewabilityConfig={viewabilityConfig}
        onViewableItemsChanged={onViewableItemsChanged}
        onScroll={(e) => {
          offsetRef.current = e.nativeEvent.contentOffset.y;
        }}
        scrollEventThrottle={16}
      />
    </View>
  );

  const renderAnalysisTab = () => (
    <View style={styles.tabContent}>
      <View style={styles.analysisCard}>
        <Text style={styles.analysisTitle}>分析</Text>
        <Text style={styles.analysisBody}>
          基于最近 6 个周期的记录，计算平均经期和周期长度，后续会展示趋势和预测准确度。
        </Text>
      </View>
    </View>
  );

  return (
    <View style={styles.container}>
      <Stack.Screen options={{ headerShown: false }} />
      <LinearGradient
        colors={['#fdf1ff', '#f3f4ff', '#f7f8ff']}
        style={StyleSheet.absoluteFill}
        start={{ x: 0, y: 0 }}
        end={{ x: 0, y: 1 }}
      />

      <View style={styles.header}>
        <TouchableOpacity onPress={() => router.back()} style={styles.headerIcon}>
          <Ionicons name="chevron-back" size={22} color="#0f172a" />
        </TouchableOpacity>
        <Text style={styles.headerTitle}>生理周期</Text>
        <TouchableOpacity style={styles.headerIcon}>
          <Ionicons name="settings-outline" size={20} color="#0f172a" />
        </TouchableOpacity>
      </View>

      <View style={styles.tabSwitcher}>
        {([
          { key: 'cycle', label: '生理周期' },
          { key: 'analysis', label: '分析' },
        ] as { key: TabKey; label: string }[]).map((tab) => {
          const active = activeTab === tab.key;
          return (
            <TouchableOpacity
              key={tab.key}
              style={[styles.tabPill, active && styles.tabPillActive]}
              onPress={() => setActiveTab(tab.key)}
              activeOpacity={0.9}
            >
              <Text style={[styles.tabLabel, active && styles.tabLabelActive]}>
                {tab.label}
              </Text>
            </TouchableOpacity>
          );
        })}
      </View>

      {activeTab === 'cycle' ? renderCycleTab() : renderAnalysisTab()}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: 52,
    paddingHorizontal: 16,
    backgroundColor: 'transparent',
  },
  header: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    marginBottom: 12,
  },
  headerIcon: {
    width: 36,
    height: 36,
    borderRadius: 18,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'rgba(255,255,255,0.9)',
  },
  headerTitle: {
    fontSize: 18,
    fontWeight: '800',
    color: '#0f172a',
    fontFamily: 'AliBold',
  },
  tabSwitcher: {
    flexDirection: 'row',
    backgroundColor: 'rgba(255,255,255,0.7)',
    borderRadius: 18,
    padding: 4,
    marginBottom: 16,
  },
  tabPill: {
    flex: 1,
    alignItems: 'center',
    paddingVertical: 10,
    borderRadius: 14,
  },
  tabPillActive: {
    backgroundColor: '#fff',
    shadowColor: '#000',
    shadowOpacity: 0.08,
    shadowOffset: { width: 0, height: 8 },
    shadowRadius: 10,
    elevation: 3,
  },
  tabLabel: {
    color: '#4b5563',
    fontWeight: '600',
    fontFamily: 'AliRegular',
  },
  tabLabelActive: {
    color: '#0f172a',
    fontFamily: 'AliBold',
  },
  tabContent: {
    flex: 1,
  },
  legendRow: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    gap: 12,
    marginBottom: 12,
    paddingHorizontal: 4,
  },
  legendItem: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  legendDot: {
    width: 16,
    height: 16,
    borderRadius: 8,
    marginRight: 6,
  },
  legendDotRing: {
    borderWidth: 2,
    borderColor: '#fff',
  },
  legendLabel: {
    fontSize: 13,
    color: '#111827',
    fontFamily: 'AliRegular',
  },
  selectedCard: {
    backgroundColor: '#fff',
    borderRadius: 16,
    paddingVertical: 10,
    paddingHorizontal: 12,
    marginBottom: 10,
    shadowColor: '#000',
    shadowOpacity: 0.08,
    shadowRadius: 10,
    shadowOffset: { width: 0, height: 8 },
    elevation: 3,
  },
  selectedStatus: {
    fontSize: 14,
    color: '#111827',
    fontWeight: '700',
    fontFamily: 'AliBold',
  },
  tipCard: {
    backgroundColor: '#f4f3ff',
    borderRadius: 14,
    padding: 12,
    marginTop: 10,
    borderWidth: 1,
    borderColor: '#ede9fe',
  },
  tipTitle: {
    fontSize: 14,
    color: '#111827',
    fontWeight: '700',
    marginBottom: 4,
    fontFamily: 'AliBold',
  },
  tipDesc: {
    fontSize: 12,
    color: '#6b7280',
    lineHeight: 18,
    marginBottom: 8,
    fontFamily: 'AliRegular',
  },
  tipButton: {
    backgroundColor: Colors.light.primary,
    paddingVertical: 10,
    borderRadius: 12,
    alignItems: 'center',
  },
  tipButtonText: {
    color: '#fff',
    fontSize: 14,
    fontWeight: '700',
    fontFamily: 'AliBold',
  },
  tipSecondaryButton: {
    backgroundColor: '#fff',
    paddingVertical: 10,
    borderRadius: 12,
    alignItems: 'center',
    borderWidth: 1,
    borderColor: '#e5e7eb',
  },
  tipSecondaryButtonText: {
    color: '#0f172a',
    fontSize: 14,
    fontWeight: '700',
    fontFamily: 'AliBold',
  },
  inlineTipCard: {
    backgroundColor: '#e8e7ff',
    borderRadius: 18,
    paddingVertical: 10,
    paddingHorizontal: 12,
    shadowColor: '#000',
    shadowOpacity: 0.04,
    shadowRadius: 6,
    shadowOffset: { width: 0, height: 2 },
    elevation: 1,
  },
  inlineTipPointer: {
    position: 'absolute',
    top: -6,
    width: 12,
    height: 12,
    marginLeft: -6,
    backgroundColor: '#e8e7ff',
    transform: [{ rotate: '45deg' }],
    borderRadius: 3,
  },
  inlineTipRow: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    gap: 8,
  },
  inlineTipDate: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 6,
  },
  inlineTipDateText: {
    fontSize: 14,
    color: '#111827',
    fontWeight: '800',
    fontFamily: 'AliBold',
  },
  inlinePrimaryBtn: {
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: Colors.light.primary,
    paddingHorizontal: 12,
    paddingVertical: 8,
    borderRadius: 14,
    gap: 6,
  },
  inlinePrimaryText: {
    color: '#fff',
    fontSize: 13,
    fontWeight: '700',
    fontFamily: 'AliBold',
  },
  inlineSecondaryBtn: {
    paddingHorizontal: 12,
    paddingVertical: 8,
    borderRadius: 14,
    backgroundColor: '#fff',
    borderWidth: 1,
    borderColor: '#d1d5db',
  },
  inlineSecondaryText: {
    color: '#111827',
    fontSize: 13,
    fontWeight: '700',
    fontFamily: 'AliBold',
  },
  monthCard: {
    backgroundColor: '#fff',
    borderRadius: 16,
    padding: 14,
    marginBottom: 12,
    shadowColor: '#000',
    shadowOpacity: 0.08,
    shadowRadius: 8,
    shadowOffset: { width: 0, height: 6 },
    elevation: 2,
  },
  monthHeader: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    marginBottom: 8,
  },
  monthTitle: {
    fontSize: 17,
    fontWeight: '800',
    color: '#0f172a',
    fontFamily: 'AliBold',
  },
  monthSubtitle: {
    fontSize: 12,
    color: '#6b7280',
    fontFamily: 'AliRegular',
  },
  weekRow: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    marginBottom: 6,
    paddingHorizontal: 4,
  },
  weekLabel: {
    width: '14.28%',
    textAlign: 'center',
    fontSize: 12,
    color: '#94a3b8',
    fontFamily: 'AliRegular',
  },
  monthGrid: {
    flexDirection: 'column',
  },
  daysRow: {
    flexDirection: 'row',
  },
  dayCell: {
    width: '14.28%',
    alignItems: 'center',
    marginVertical: 6,
  },
  inlineTipContainer: {
    paddingBottom: 6,
    marginBottom: 6,
  },
  dayCircle: {
    width: 40,
    height: 40,
    borderRadius: 20,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: '#f3f4f6',
  },
  dayCircleSelected: {
    borderWidth: 2,
    borderColor: Colors.light.primary,
  },
  todayOutline: {
    borderWidth: 2,
    borderColor: '#94a3b8',
  },
  dayLabel: {
    fontSize: 15,
    fontFamily: 'AliBold',
  },
  dayLabelDefault: {
    color: '#111827',
  },
  todayText: {
    fontSize: 10,
    color: '#9ca3af',
    marginTop: 2,
    fontFamily: 'AliRegular',
  },
  listContent: {
    paddingBottom: 80,
  },
  analysisCard: {
    backgroundColor: '#fff',
    borderRadius: 16,
    padding: 16,
    marginTop: 8,
    shadowColor: '#000',
    shadowOpacity: 0.08,
    shadowRadius: 10,
    shadowOffset: { width: 0, height: 6 },
    elevation: 3,
  },
  analysisTitle: {
    fontSize: 17,
    fontWeight: '800',
    color: '#0f172a',
    marginBottom: 8,
    fontFamily: 'AliBold',
  },
  analysisBody: {
    fontSize: 14,
    color: '#6b7280',
    lineHeight: 20,
    fontFamily: 'AliRegular',
  },
});
