import React, { useEffect, useState } from 'react';
import { View, Text, TouchableOpacity, ScrollView, Alert } from 'react-native';
import { useNavigation } from '@react-navigation/native';
import moment from 'moment';

import { PageWrapper, Header, Input, WarningModal } from 'src/components';
import RegionItem from '../Components/RegionItemNew';
import RangeCalendar from 'src/components/Calendars/RangeCalendar';

import { StoreType, storage } from 'src/storage';
import { Colors } from 'src/theme';
import { NAVIGATION_PAGES } from 'src/types';
import { RegionAddData } from '../utils/types';
import {
  useGetTripQuery,
  usePostDeleteTripMutation,
  usePostUpdateTripMutation,
  usePostSetNewTripMutation
} from '@api/trips';
import { styles } from './styles';

import { ActivityIndicator } from 'react-native-paper';
import ActionSheet, { ActionSheetRef } from 'react-native-actions-sheet';
import SummarySheet from '../Components/SummarySheet';

interface DateValue {
  year: number | null;
  month: number | null;
  day: number | null;
}

interface RegionWithDates extends RegionAddData {
  _instanceId?: string;
  visitStartDate?: DateValue | null;
  visitEndDate?: DateValue | null;
  year_from?: number;
  year_to?: number;
  month_from?: number;
  month_to?: number;
  day_from?: number | null;
  day_to?: number | null;
}

const AddNewTripScreen = ({ route }: { route: any }) => {
  const editTripId = route.params?.editTripId ?? null;
  const token = storage.get('token', StoreType.STRING) as string;
  const { data: editData } = useGetTripQuery(token, editTripId, Boolean(editTripId));
  const navigation = useNavigation();
  const [description, setDescription] = useState<string>('');
  const [regions, setRegions] = useState<RegionWithDates[] | null>(null);
  const [disabled, setDisabled] = useState(true);
  const [isLoading, setIsLoading] = useState<string | null>(null);
  const [isWarningModalVisible, setIsWarningModalVisible] = useState(false);

  const [pendingDelete, setPendingDelete] = useState(false);

  const [calendarVisibleForIndex, setCalendarVisibleForIndex] = useState<number | null>(null);

  const [regionErrors, setRegionErrors] = useState<{ [instanceId: string]: string }>({});
  const [shouldScrollToEmpty, setShouldScrollToEmpty] = useState(false);

  const summarySheetRef = React.useRef<ActionSheetRef>(null);

  const [summaryData, setSummaryData] = useState({
    totalDays: 0,
    perRegion: []
  });

  const [pendingAction, setPendingAction] = useState<'save' | 'update' | null>(null);
  const isClosingRef = React.useRef<boolean>(null);

  const { mutate: saveNewTrip } = usePostSetNewTripMutation();
  const { mutate: updateTrip } = usePostUpdateTripMutation();
  const { mutate: deleteTrip } = usePostDeleteTripMutation();

  const scrollRef = React.useRef<ScrollView>(null);
  const instanceCounterRef = React.useRef(1);

  const scrollToError = (errors: { [instanceId: string]: string }) => {
    if (!regions || !Object.keys(errors).length) return;
    const firstInstanceId = Object.keys(errors)[0];
    const idx = regions.findIndex((r) => r._instanceId === firstInstanceId);
    if (idx === -1) return;
    const itemHeight = 160;
    scrollRef.current?.scrollTo({ y: idx * itemHeight, animated: true });
  };

  const scrollToEmpty = () => {
    if (!regions?.length) return;

    const idx = regions.findIndex((r) => {
      const startOK = isFullDate(r.visitStartDate);
      const endOK = isFullDate(r.visitEndDate);
      return !(startOK && endOK);
    });

    if (idx === -1) return;

    const itemHeight = 160;
    scrollRef.current?.scrollTo({
      y: idx * itemHeight,
      animated: true
    });
  };

  const computeTripSummary = (list: RegionWithDates[]) => {
    const daySet = new Set<string>();
    const perRegionMap: Record<string, any> = {};

    for (const r of list) {
      const isTransit = r.quality === 1;

      if (isTransit) {
        const key = `${r.id}_transit`;

        if (!perRegionMap[key]) {
          perRegionMap[key] = {
            id: r.id,
            name: r.region_name,
            days: 0,
            transit: true,
            flag1: r.flag1!,
            flag2: r.flag2 ?? null
          };
        }

        perRegionMap[key].days += 1;
        continue;
      }

      if (!isFullDate(r.visitStartDate) || !isFullDate(r.visitEndDate)) continue;

      const startISO = dateValueToISO(r.visitStartDate)!;
      const endISO = dateValueToISO(r.visitEndDate)!;

      let cursor = moment(startISO);
      const end = moment(endISO);

      let regionDays = 0;

      while (cursor.isSameOrBefore(end)) {
        daySet.add(cursor.format('YYYY-MM-DD'));
        regionDays++;
        cursor = cursor.add(1, 'day');
      }

      if (!perRegionMap[r.id]) {
        perRegionMap[r.id] = {
          id: r.id,
          name: r.region_name,
          days: 0,
          flag1: r.flag1,
          flag2: r?.flag2
        };
      }

      perRegionMap[r.id].days += regionDays;
    }

    return {
      totalDays: daySet.size,
      perRegion: Object.values(perRegionMap)
    };
  };

  const normalizeRegion = (r: RegionWithDates): RegionWithDates => ({
    ...r,
    _instanceId: r._instanceId ?? `r-${instanceCounterRef.current++}`,
    visitStartDate: r.visitStartDate ? { ...r.visitStartDate } : null,
    visitEndDate: r.visitEndDate ? { ...r.visitEndDate } : null
  });

  const autoFillAfterAppend = (list: RegionWithDates[], oldCount: number) => {
    if (!list || list.length === 0) return list;

    const updated = [...list];

    let lastWithDateIndex: number | null = null;
    for (let i = updated.length - 1; i >= 0; i--) {
      const r = updated[i];
      r._instanceId = `r-${instanceCounterRef.current++}`;
      if (
        r.visitStartDate?.year &&
        r.visitStartDate?.month &&
        r.visitStartDate?.day &&
        r.visitEndDate?.year &&
        r.visitEndDate?.month &&
        r.visitEndDate?.day
      ) {
        lastWithDateIndex = i;
        break;
      }
    }

    if (lastWithDateIndex === null || lastWithDateIndex < oldCount - 1) return updated;

    const lastDate: DateValue = updated[lastWithDateIndex].visitEndDate as DateValue;

    for (let i = lastWithDateIndex + 1; i < updated.length; i++) {
      const r = updated[i];

      const hasStart = isFullDate(r.visitStartDate);
      const hasEnd = isFullDate(r.visitEndDate);

      if (!hasStart || !hasEnd) {
        updated[i] = {
          ...r,
          _instanceId: `r-${instanceCounterRef.current++}`,
          visitStartDate: lastDate,
          visitEndDate: lastDate
        };
        break;
      }
    }

    return updated;
  };

  useEffect(() => {
    if (!shouldScrollToEmpty || !regions) return;

    requestAnimationFrame(() => {
      scrollToEmpty();
      setShouldScrollToEmpty(false);
    });
  }, [shouldScrollToEmpty, regions]);

  useEffect(() => {
    if (route.params?.regionsToSave) {
      const oldRegions = route.params.regionsToSave.filter((r: any) => r._instanceId);
      const oldCount = oldRegions.length;
      const normalized = route.params.regionsToSave.map(normalizeRegion);
      const filled = autoFillAfterAppend(normalized, oldCount);

      setRegions(filled);
      setShouldScrollToEmpty(true);
    }
  }, [route.params?.regionsToSave]);

  function extractNumberAndExtension(path: string | null) {
    if (!path) return null;
    const slashIndex = path.lastIndexOf('/');
    return path.substring(slashIndex + 1);
  }

  useEffect(() => {
    if (editData && editData.trip) {
      setDescription(editData.trip.description);
      setRegions(
        editData.trip.regions.map((region: any) => {
          const instanceId = `r-${instanceCounterRef.current++}`;
          return {
            ...region,
            _instanceId: instanceId,
            id: region.region,
            flag1: extractNumberAndExtension(region.flag1),
            flag2: extractNumberAndExtension(region.flag2),
            visitStartDate: {
              year: region.year_from || null,
              month: region.month_from || null,
              day: region.day_from || null
            },
            visitEndDate: {
              year: region.year_to || null,
              month: region.month_to || null,
              day: region.day_to || null
            },
            quality: region.quality ?? 3
          };
        })
      );
    }
  }, [editData]);

  useEffect(() => {
    setDisabled(!regions?.length);
  }, [regions]);

  const formatDateForDisplay = (d?: DateValue | null) => {
    if (!d || !d.year) return 'Select dates';
    const m = moment(`${d.year}-${d.month}-${d.day}`, 'YYYY-M-D');
    return !d.month ? m.format('YYYY') : !d.day ? m.format('MMM YYYY') : m.format('D MMM YYYY');
  };

  const dateValueToISO = (d?: DateValue | null) => {
    if (!d || !d.year) return null;
    const mm = String(d.month).padStart(2, '0');
    const dd = String(d.day).padStart(2, '0');
    return `${d.year}-${mm}-${dd}`;
  };

  const parseISOToDateValue = (iso?: string | null): DateValue | null => {
    if (!iso) return null;
    const m = moment(iso, 'YYYY-MM-DD');
    if (!m.isValid()) return null;
    return { year: m.year(), month: m.month() + 1, day: m.date() };
  };

  const validateRegionsDates = (regionsToValidate?: RegionWithDates[] | null) => {
    const list = regionsToValidate ?? regions;
    const errors: { [instanceId: string]: string } = {};

    if (!list || list.length === 0) {
      setRegionErrors(errors);
      return false;
    }

    for (let i = 0; i < list.length; i++) {
      const r = list[i];
      const s = r.visitStartDate;
      const e = r.visitEndDate;
      const id = r._instanceId ?? `idx-${i}`;

      if (!s?.year || !s?.month || !s?.day) {
        errors[id] = 'Please select visit dates';
        continue;
      }
      if (!e?.year || !e?.month || !e?.day) {
        errors[id] = 'Please select visit dates';
        continue;
      }

      const sM = moment(`${s.year}-${s.month}-${s.day}`, 'YYYY-M-D');
      const eM = moment(`${e.year}-${e.month}-${e.day}`, 'YYYY-M-D');

      if (sM.isAfter(eM)) {
        errors[id] = 'Start date cannot be after end date';
        continue;
      }

      // if (i > 0) {
      //   const prevEnd = list[i - 1]?.visitEndDate;
      //   if (prevEnd?.year) {
      //     const prevEndM = moment(`${prevEnd.year}-${prevEnd.month}-${prevEnd.day}`, 'YYYY-M-D');
      //     if (sM.isBefore(prevEndM)) {
      //       errors[i] = 'This region must start before previous';
      //       continue;
      //     }
      //   }
      // }
    }

    setRegionErrors(errors);
    return Object.keys(errors).length === 0;
  };

  const isFullDate = (d?: DateValue | null) => {
    return !!(d?.year && d?.month && d?.day);
  };

  const openRangeCalendarForRegion = (index: number) => {
    if (!regions) return;
    setCalendarVisibleForIndex(index);
  };

  const closeRangeCalendar = (startDate?: string | null, endDate?: string | null) => {
    const clickedInstanceIndex = calendarVisibleForIndex;
    setCalendarVisibleForIndex(null);

    if (clickedInstanceIndex === null || clickedInstanceIndex === undefined || !startDate) return;

    const startVal = parseISOToDateValue(startDate);
    const endVal = parseISOToDateValue(endDate ?? startDate);

    if (!startVal || !endVal) return;

    const openedInstanceId = regions?.[clickedInstanceIndex]?._instanceId;
    if (!openedInstanceId) {
      return;
    }

    const updatedBeforeSort = (regions ?? []).map((r) =>
      r._instanceId === openedInstanceId
        ? { ...r, visitStartDate: startVal, visitEndDate: endVal }
        : r
    );

    const sortKey = (r: RegionWithDates) => {
      const iso = dateValueToISO(r.visitStartDate);
      return iso ?? '9999-12-31';
    };
    const sorted = [...updatedBeforeSort].sort((a, b) => sortKey(a).localeCompare(sortKey(b)));

    const newIndex = sorted.findIndex((r) => r._instanceId === openedInstanceId);

    if (newIndex !== -1) {
      const next = sorted[newIndex + 1];
      if (next && !isFullDate(next.visitStartDate)) {
        sorted[newIndex + 1] = {
          ...next,
          visitStartDate: endVal,
          visitEndDate: endVal
        };
      }
      const prev = sorted[newIndex - 1];
      if (prev && !isFullDate(prev.visitStartDate)) {
        sorted[newIndex - 1] = {
          ...prev,
          visitStartDate: startVal,
          visitEndDate: startVal
        };
      }
    }

    setRegions(sorted);

    validateRegionsDates(sorted);

    setRegionErrors((prev) => {
      const clone = { ...prev };
      delete clone[clickedInstanceIndex];
      return clone;
    });
  };

  const moveRegionUp = (index: number) => {
    if (index <= 0 || !regions) return;
    const newRegions = [...regions];
    [newRegions[index - 1], newRegions[index]] = [newRegions[index], newRegions[index - 1]];
    setRegions(newRegions);
  };

  const moveRegionDown = (index: number) => {
    if (!regions || index >= regions.length - 1) return;
    const newRegions = [...regions];
    [newRegions[index + 1], newRegions[index]] = [newRegions[index], newRegions[index + 1]];
    setRegions(newRegions);
  };

  const handleDeleteRegion = (index: number) => {
    if (!regions) return;
    const updated = [...regions];
    updated.splice(index, 1);
    setRegions(updated);
  };

  const handleDeleteTrip = async () => {
    setIsWarningModalVisible(false);
    setPendingDelete(true);
  };

  const computePayloadDates = (regionsList: RegionWithDates[]) => {
    if (!regionsList || regionsList.length === 0) return { date_from: null, date_to: null };

    const starts = regionsList.map((r) => dateValueToISO(r.visitStartDate) as string);
    const ends = regionsList.map((r) => dateValueToISO(r.visitEndDate) as string);

    const minStart = starts.reduce(
      (acc, cur) => (!acc || cur < acc ? cur : acc),
      null as string | null
    );
    const maxEnd = ends.reduce(
      (acc, cur) => (!acc || cur > acc ? cur : acc),
      null as string | null
    );

    return { date_from: minStart, date_to: maxEnd };
  };

  const performSaveNewTrip = async () => {
    if (!regions) return;

    try {
      setIsLoading('save');
      const regionsData = regions.map((region) => {
        return {
          id: region.id,
          quality: 3,
          hidden: region.hidden,
          year_from: region.visitStartDate?.year || null,
          year_to: region.visitEndDate?.year || null,
          month_from: region.visitStartDate?.month || null,
          month_to: region.visitEndDate?.month || null,
          day_from: region.visitStartDate?.day || null,
          day_to: region.visitEndDate?.day || null
        };
      });

      // if (regionsData.length > 30) {
      //   Alert.alert('One trip cannot have more than 30 regions.');
      //   setIsLoading(null);
      //   return;
      // }

      const { date_from, date_to } = computePayloadDates(regions);

      saveNewTrip(
        {
          token,
          date_from,
          date_to,
          description,
          regions: regionsData
        },
        {
          onSuccess: (res) => {
            if (res && res.result === 'OK') {
              navigation.popTo(...([NAVIGATION_PAGES.TRIPS_2025, { saved: true }] as never));
            }
            setIsLoading(null);
          },
          onError: () => {
            setIsLoading(null);
          }
        }
      );
    } catch (err) {
      console.log('Save trip failed', err);
    }
  };

  const performUpdateTrip = async () => {
    if (!regions) return;

    try {
      setIsLoading('update');
      const regionsData = regions.map((region) => {
        return {
          id: region.id,
          quality: region.quality ?? 3,
          hidden: region.hidden,
          year_from: region.visitStartDate?.year || null,
          year_to: region.visitEndDate?.year || null,
          month_from: region.visitStartDate?.month || null,
          month_to: region.visitEndDate?.month || null,
          day_from: region.visitStartDate?.day || null,
          day_to: region.visitEndDate?.day || null
        };
      });

      // if (regionsData.length > 30) {
      //   Alert.alert('One trip cannot have more than 30 regions.');
      //   setIsLoading(null);
      //   return;
      // }

      const { date_from, date_to } = computePayloadDates(regions);

      updateTrip(
        {
          token,
          trip_id: editTripId,
          date_from,
          date_to,
          description,
          regions: regionsData
        },
        {
          onSuccess: (res) => {
            if (res && res.result === 'OK') {
              navigation.popTo(...([NAVIGATION_PAGES.TRIPS_2025, { updated: true }] as never));
            }
            setIsLoading(null);
          },
          onError: () => {
            setIsLoading(null);
          }
        }
      );
    } catch (err) {
      console.log('Update trip failed', err);
    }
  };

  const handleSaveNewTrip = () => {
    if (regions) {
      if (!validateRegionsDates(regions)) {
        scrollToError(regionErrors);
        return;
      }

      const summary = computeTripSummary(regions);
      if (summary) {
        setSummaryData({
          ...summary,
          perRegion: summary.perRegion?.sort((a: any, b: any) => b.days - a.days) || []
        });
      } else {
        setSummaryData({ totalDays: 0, perRegion: [] });
      }
      setPendingAction('save');

      summarySheetRef.current?.show();
    }
  };

  const handleUpdateTrip = () => {
    if (regions) {
      if (!validateRegionsDates(regions)) {
        scrollToError(regionErrors);
        return;
      }

      const summary = computeTripSummary(regions);
      if (summary) {
        setSummaryData({
          ...summary,
          perRegion: summary.perRegion?.sort((a: any, b: any) => b.days - a.days) || []
        });
      } else {
        setSummaryData({ totalDays: 0, perRegion: [] });
      }
      setPendingAction('update');

      summarySheetRef.current?.show();
    }
  };

  return (
    <PageWrapper style={{ flex: 1 }}>
      <Header label={editTripId ? 'Edit Trip' : 'Add New Trip'} />
      <ScrollView
        ref={scrollRef}
        contentContainerStyle={{ flexGrow: 1, gap: 16 }}
        showsVerticalScrollIndicator={false}
      >
        <Input
          // placeholder="Add description and all interesting moments of your trip"
          inputMode={'text'}
          onChange={(text) => setDescription(text)}
          value={description}
          header="Description"
          height={36}
          multiline={true}
        />

        <View style={{ marginBottom: 8 }}>
          <Text style={styles.regionsLabel}>Regions</Text>
          {regions && regions.length ? (
            <View style={styles.regionsContainer}>
              {regions.map((region, index) => {
                const startLabel = formatDateForDisplay(region.visitStartDate);
                const endLabel = formatDateForDisplay(region.visitEndDate);
                const datesLabel =
                  region.visitStartDate?.year &&
                  region.visitEndDate?.year &&
                  dateValueToISO(region.visitStartDate) === dateValueToISO(region.visitEndDate)
                    ? startLabel
                    : region.visitStartDate?.year && region.visitEndDate?.year
                      ? `${startLabel} - ${endLabel}`
                      : 'Select visit dates';

                return (
                  <RegionItem
                    key={`${region.id}-${index}`}
                    region={region}
                    index={index}
                    total={regions.length}
                    onDelete={() => handleDeleteRegion(index)}
                    onSelectDates={() => openRangeCalendarForRegion(index)}
                    datesLabel={datesLabel}
                    onMoveUp={() => moveRegionUp(index)}
                    onMoveDown={() => moveRegionDown(index)}
                    errorMessage={regionErrors[region?._instanceId ?? index]}
                    startLabel={startLabel}
                    endLabel={endLabel}
                  />
                );
              })}
            </View>
          ) : (
            <Text style={styles.noRegiosText}>No regions at the moment</Text>
          )}
        </View>
      </ScrollView>

      <View style={{ flexDirection: 'column', gap: 6, backgroundColor: 'transparent' }}>
        <TouchableOpacity
          style={[styles.addRegionBtn]}
          onPress={() =>
            navigation.navigate(
              ...([
                NAVIGATION_PAGES.ADD_REGIONS_NEW,
                { regionsParams: regions, editId: editTripId }
              ] as never)
            )
          }
        >
          <Text style={styles.addRegionBtntext}>Add new visit</Text>
        </TouchableOpacity>
        <View style={styles.tabContainer}>
          {editTripId ? (
            <>
              <TouchableOpacity
                style={[styles.tabStyle, styles.deleteTab]}
                onPress={() => setIsWarningModalVisible(true)}
                disabled={isLoading === 'delete'}
              >
                {isLoading === 'delete' ? (
                  <ActivityIndicator size={18} color={Colors.RED} />
                ) : (
                  <Text style={[styles.tabText, styles.deleteTabText]}>Delete trip</Text>
                )}
              </TouchableOpacity>
              <TouchableOpacity
                style={[
                  styles.tabStyle,
                  styles.addNewTab,
                  disabled && { backgroundColor: Colors.LIGHT_GRAY, borderColor: Colors.LIGHT_GRAY }
                ]}
                onPress={handleUpdateTrip}
                disabled={disabled || isLoading === 'update'}
              >
                {isLoading === 'update' ? (
                  <ActivityIndicator size={18} color={Colors.WHITE} />
                ) : (
                  <Text style={[styles.tabText, styles.addNewTabText]}>Save trip</Text>
                )}
              </TouchableOpacity>
            </>
          ) : (
            <TouchableOpacity
              style={[
                styles.tabStyle,
                styles.addNewTab,
                disabled && { backgroundColor: Colors.LIGHT_GRAY, borderColor: Colors.LIGHT_GRAY },
                { paddingVertical: 12 }
              ]}
              onPress={handleSaveNewTrip}
              disabled={disabled || isLoading === 'save'}
            >
              {isLoading === 'save' ? (
                <ActivityIndicator size={18} color={Colors.WHITE} />
              ) : (
                <Text style={[styles.tabText, styles.addNewTabText]}>Save new trip</Text>
              )}
            </TouchableOpacity>
          )}
        </View>
      </View>

      <RangeCalendar
        isModalVisible={calendarVisibleForIndex !== null}
        allowRangeSelection={true}
        closeModal={(startDate?: string | null, endDate?: string | null) =>
          closeRangeCalendar(startDate, endDate)
        }
        initialStartDate={
          calendarVisibleForIndex !== null &&
          regions?.[calendarVisibleForIndex]?.visitStartDate &&
          regions[calendarVisibleForIndex].visitStartDate?.day
            ? `${regions[calendarVisibleForIndex].visitStartDate.year}-${regions[calendarVisibleForIndex].visitStartDate.month}-${regions[calendarVisibleForIndex].visitStartDate.day}`
            : undefined
        }
        initialEndDate={
          calendarVisibleForIndex !== null &&
          regions?.[calendarVisibleForIndex]?.visitEndDate &&
          regions[calendarVisibleForIndex].visitEndDate?.day
            ? `${regions[calendarVisibleForIndex].visitEndDate.year}-${regions[calendarVisibleForIndex].visitEndDate.month}-${regions[calendarVisibleForIndex].visitEndDate.day}`
            : undefined
        }
        initialYear={
          calendarVisibleForIndex !== null &&
          regions?.[calendarVisibleForIndex]?.visitStartDate?.year
            ? regions[calendarVisibleForIndex].visitStartDate.year
            : undefined
        }
        initialMonth={
          calendarVisibleForIndex !== null &&
          regions?.[calendarVisibleForIndex]?.visitStartDate?.month
            ? regions[calendarVisibleForIndex].visitStartDate.month
            : undefined
        }
        withHint={true}
      />
      <WarningModal
        type={'delete'}
        isVisible={isWarningModalVisible}
        onClose={() => setIsWarningModalVisible(false)}
        title="Delete Trip"
        message="Are you sure you want to delete your trip?"
        action={handleDeleteTrip}
        onModalHide={() => {
          if (pendingDelete) {
            setPendingDelete(false);
            setIsLoading('delete');
            deleteTrip(
              {
                token,
                trip_id: editTripId
              },
              {
                onSuccess: (res) => {
                  if (res && res.result === 'OK') {
                    navigation.popTo(
                      ...([NAVIGATION_PAGES.TRIPS_2025, { deleted: true }] as never)
                    );
                  }
                  setIsLoading(null);
                },
                onError: () => {
                  setIsLoading(null);
                }
              }
            );
          }
        }}
      />

      <SummarySheet
        ref={summarySheetRef}
        summary={summaryData}
        onConfirm={async () => {
          summarySheetRef.current?.hide();
          isClosingRef.current = true;
        }}
        onClose={async () => {
          if (!isClosingRef.current) return;
          if (pendingAction === 'save') performSaveNewTrip();
          if (pendingAction === 'update') performUpdateTrip();
          isClosingRef.current = false;
        }}
      />
    </PageWrapper>
  );
};

export default AddNewTripScreen;
