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 {
  FlatList,
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
} from 'react-native';
import { useTranslation } from 'react-i18next';

import { InlineTip, ITEM_HEIGHT, Legend, MonthBlock } from '@/components/menstrual-cycle';
import {
  deleteMenstrualFlow,
  fetchMenstrualFlowSamples,
  saveMenstrualFlow
} from '@/utils/health';
import {
  buildMenstrualTimeline,
  convertHealthKitSamplesToCycleRecords,
  CycleRecord,
  DEFAULT_PERIOD_LENGTH
} from '@/utils/menstrualCycle';

type TabKey = 'cycle' | 'analysis';

export default function MenstrualCycleScreen() {
  const router = useRouter();
  const { t } = useTranslation();
  const [records, setRecords] = useState<CycleRecord[]>([]);
  const [windowConfig, setWindowConfig] = useState({ before: 2, after: 3 });

  // Load data from HealthKit
  useEffect(() => {
    const loadData = async () => {
      // Calculate date range based on windowConfig
      const today = dayjs();
      const startDate = today.subtract(windowConfig.before, 'month').startOf('month').toDate();
      const endDate = today.add(windowConfig.after, 'month').endOf('month').toDate();

      const samples = await fetchMenstrualFlowSamples(startDate, endDate);
      const convertedRecords = convertHealthKitSamplesToCycleRecords(samples);
      setRecords(convertedRecords);
    };

    loadData();
  }, [windowConfig]);

  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 = async () => {
    if (selectedDate.isAfter(dayjs(), 'day')) return;

    // Check if the selected date is already covered
    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;

    // Optimistic Update
    const originalRecords = [...records];
    setRecords((prev) => {
      const updated = [...prev];
      // Logic for optimistic UI update (same as original logic)
      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');
      });
      const nextRecordIndex = updated.findIndex((r) => {
        return dayjs(r.startDate).subtract(1, 'day').isSame(selectedDate, 'day');
      });

      if (prevRecordIndex !== -1 && nextRecordIndex !== -1) {
        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 };
        updated.splice(nextRecordIndex, 1);
      } else if (prevRecordIndex !== -1) {
        const prevRecord = updated[prevRecordIndex];
        updated[prevRecordIndex] = {
          ...prevRecord,
          periodLength: (prevRecord.periodLength ?? DEFAULT_PERIOD_LENGTH) + 1,
        };
      } else if (nextRecordIndex !== -1) {
        const nextRecord = updated[nextRecordIndex];
        updated[nextRecordIndex] = {
          ...nextRecord,
          startDate: selectedDate.format('YYYY-MM-DD'),
          periodLength: (nextRecord.periodLength ?? DEFAULT_PERIOD_LENGTH) + 1,
        };
      } else {
        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());
    });

    try {
      // Determine what to save to HealthKit
      // If we are merging or extending, we are effectively adding one day of flow
      // If we are creating a new record, we default to 7 days
      // However, accurate HealthKit logging should be per day.
      // The previous UI logic "creates" a 7-day period for a single tap.
      // We should replicate this behavior in HealthKit for consistency.

      const isNewIsolatedRecord = !records.some((r) => {
        const start = dayjs(r.startDate);
        const end = start.add((r.periodLength ?? DEFAULT_PERIOD_LENGTH) - 1, 'day');
        // Check adjacency
        return (
          end.add(1, 'day').isSame(selectedDate, 'day') ||
          dayjs(r.startDate).subtract(1, 'day').isSame(selectedDate, 'day')
        );
      });

      if (isNewIsolatedRecord) {
        // Save 7 days of flow starting from selectedDate
        const promises = [];
        for (let i = 0; i < 7; i++) {
          const date = selectedDate.add(i, 'day');
          // Don't save future dates if they exceed today (though logic allows predicting)
          // But for flow logging, we usually only log past/present.
          // However, UI allows setting a period that might extend slightly?
          // Let's stick to the selected date logic.
          // Wait, if I tap "Mark Start", it creates a 7 day period.
          // Should I write 7 samples? Yes, to match the UI state.
          promises.push(saveMenstrualFlow(date.toDate(), 1, i === 0)); // 1=unspecified
        }
        await Promise.all(promises);
      } else {
        // Just adding a single day to bridge/extend
        await saveMenstrualFlow(selectedDate.toDate(), 1, false);
      }
    } catch (error) {
      console.error('Failed to save to HealthKit', error);
      // Revert optimistic update
      setRecords(originalRecords);
    }
  };

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

    // Optimistic Update
    const originalRecords = [...records];
    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; // Remove entire record (or start of it)
        updated.push({ ...record, periodLength: diff }); // Shorten it
      });
      return updated;
    });

    try {
      // Logic:
      // 1. Find the record covering the target date
      const record = records.find((r) => {
        const start = dayjs(r.startDate);
        const end = start.add((r.periodLength ?? DEFAULT_PERIOD_LENGTH) - 1, 'day');
        return (
          (target.isSame(start, 'day') || target.isAfter(start, 'day')) &&
          (target.isSame(end, 'day') || target.isBefore(end, 'day'))
        );
      });

      if (record) {
        const start = dayjs(record.startDate);
        const diff = target.diff(start, 'day');

        if (diff === 0) {
          // If cancelling the start date, the UI removes the ENTIRE period record.
          // So we should delete all samples for this period range.
          const periodLength = record.periodLength ?? DEFAULT_PERIOD_LENGTH;
          const endDate = start.add(periodLength - 1, 'day');
          await deleteMenstrualFlow(start.toDate(), endDate.toDate());
        } else {
          // If cancelling a middle/end date, the UI shortens the period to end BEFORE target.
          // So we delete from target date onwards to the original end date.
          const periodLength = record.periodLength ?? DEFAULT_PERIOD_LENGTH;
          const originalEnd = start.add(periodLength - 1, 'day');
          // Delete from target to originalEnd
          await deleteMenstrualFlow(target.toDate(), originalEnd.toDate());
        }
      }
    } catch (error) {
      console.error('Failed to delete from HealthKit', error);
      setRecords(originalRecords);
    }
  };

  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 listData = useMemo(() => {
    return timeline.months.map((m) => ({
      type: 'month' as const,
      id: m.id,
      month: m,
    }));
  }, [timeline.months]);

  const renderInlineTip = (columnIndex: number) => (
    <InlineTip
      selectedDate={selectedDate}
      selectedInfo={selectedInfo}
      columnIndex={columnIndex}
      onMarkStart={handleMarkStart}
      onCancelMark={handleCancelMark}
    />
  );

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


      <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}>{t('menstrual.screen.analysis.title')}</Text>
        <Text style={styles.analysisBody}>
          {t('menstrual.screen.analysis.description')}
        </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}>{t('menstrual.screen.header')}</Text>
        <TouchableOpacity style={styles.headerIcon}>
          <Ionicons name="settings-outline" size={20} color="#0f172a" />
        </TouchableOpacity>
      </View>

      <View style={styles.tabSwitcher}>
        {([
          { key: 'cycle', label: t('menstrual.screen.tabs.cycle') },
          { key: 'analysis', label: t('menstrual.screen.tabs.analysis') },
        ] 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,
  },

  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',
  },

  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',
  },
});
