import { AntDesign, Ionicons } from "@expo/vector-icons";
import React, { useCallback, useEffect, useState } from "react";
import { Button, Checkbox, Text, View } from "react-native-ui-lib";
import { ScrollView, StyleSheet } from "react-native";
import { colorMap } from "@/contexts/SettingsContext";
import { TouchableOpacity } from "react-native-gesture-handler";
import { fetchGoogleCalendarEvents } from "@/calendar-integration/google-calendar-utils";
import { fetchMicrosoftCalendarEvents } from "@/calendar-integration/microsoft-calendar-utils";
import { useCreateEventFromProvider } from "@/hooks/firebase/useCreateEvent";
import { useAuthContext } from "@/contexts/AuthContext";
import { useUpdateUserData } from "@/hooks/firebase/useUpdateUserData";
import debounce from "debounce";
import AppleIcon from "@/assets/svgs/AppleIcon";
import GoogleIcon from "@/assets/svgs/GoogleIcon";
import OutlookIcon from "@/assets/svgs/OutlookIcon";
import * as AuthSession from "expo-auth-session";
import * as Google from "expo-auth-session/providers/google";
import * as WebBrowser from "expo-web-browser";

const googleConfig = {
  androidClientId:
    "406146460310-2u67ab2nbhu23trp8auho1fq4om29fc0.apps.googleusercontent.com",
  iosClientId:
    "406146460310-2u67ab2nbhu23trp8auho1fq4om29fc0.apps.googleusercontent.com",
  webClientId:
    "406146460310-2u67ab2nbhu23trp8auho1fq4om29fc0.apps.googleusercontent.com",
  scopes: [
    "email",
    "profile",
    "https://www.googleapis.com/auth/calendar.events.owned",
  ],
};

const microsoftConfig = {
  clientId: "13c79071-1066-40a9-9f71-b8c4b138b4af", // Replace with your Microsoft client ID
  redirectUri: AuthSession.makeRedirectUri({ path: "settings" }), // Generate redirect URI automatically for Expo
  scopes: [
    "openid",
    "profile",
    "email",
    "offline_access",
    "Calendars.ReadWrite", // Scope for reading calendar events
  ],
  authorizationEndpoint:
    "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
  tokenEndpoint: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
};

const CalendarSettingsPage = (props: {
  setSelectedPage: (page: number) => void;
}) => {
  const [startDate, setStartDate] = useState<boolean>(false);
  const { profileData } = useAuthContext();

  const [selectedColor, setSelectedColor] = useState<string>(
    profileData?.eventColor ?? colorMap.pink
  );
  const [previousSelectedColor, setPreviousSelectedColor] = useState<string>(
    profileData?.eventColor ?? colorMap.pink
  );

  const { mutateAsync: createEventFromProvider } = useCreateEventFromProvider();
  const { mutateAsync: updateUserData } = useUpdateUserData();

  WebBrowser.maybeCompleteAuthSession();
  const [request, response, promptAsync] = Google.useAuthRequest(googleConfig);

  useEffect(() => {
    signInWithGoogle();
  }, [response]);

  const fetchAndSaveGoogleEvents = () => {
    console.log("fetch");
    const timeMin = new Date(new Date().setHours(0, 0, 0, 0));
    const timeMax = new Date(
      new Date(new Date().setHours(0, 0, 0, 0)).setDate(timeMin.getDate() + 30)
    );

    fetchGoogleCalendarEvents(
      profileData?.googleToken,
      timeMin.toISOString().slice(0, -5) + "Z",
      timeMax.toISOString().slice(0, -5) + "Z"
    ).then((response) => {
      response?.forEach((item) => saveData(item));
    });
  };

  async function saveData(item: any) {
    await createEventFromProvider(item);
  }

  const fetchAndSaveMicrosoftEvents = () => {
    const startDateTime = new Date(new Date().setHours(0, 0, 0, 0));
    const endDateTime = new Date(
      new Date(new Date().setHours(0, 0, 0, 0)).setDate(
        startDateTime.getDate() + 30
      )
    );

    fetchMicrosoftCalendarEvents(
      profileData?.microsoftToken,
      startDateTime.toISOString().slice(0, -5) + "Z",
      endDateTime.toISOString().slice(0, -5) + "Z"
    ).then((response) => {
      console.log(response);
      response?.forEach((item) => saveData(item));
    });
  };

  const signInWithGoogle = async () => {
    try {
      // Attempt to retrieve user information from AsyncStorage
      if (response?.type === "success") {
        console.log(response.authentication);
        await updateUserData({
          newUserData: { googleToken: response.authentication?.accessToken },
        });
      }
    } catch (error) {
      // Handle any errors that occur during AsyncStorage retrieval or other operations
      console.error("Error retrieving user data from AsyncStorage:", error);
    }
  };

  const handleMicrosoftSignIn = async () => {
    try {
      console.log("Starting Microsoft sign-in...");

      const authRequest = new AuthSession.AuthRequest({
        clientId: microsoftConfig.clientId,
        scopes: microsoftConfig.scopes,
        redirectUri: microsoftConfig.redirectUri,
        responseType: AuthSession.ResponseType.Code,
        usePKCE: true, // Enable PKCE
      });

      console.log("Auth request created:", authRequest);

      const authResult = await authRequest.promptAsync({
        authorizationEndpoint: microsoftConfig.authorizationEndpoint,
      });

      console.log("Auth result:", authResult);

      if (authResult.type === "success" && authResult.params?.code) {
        const code = authResult.params.code;
        console.log("Authorization code received:", code);

        // Exchange authorization code for tokens
        const tokenResponse = await fetch(microsoftConfig.tokenEndpoint, {
          method: "POST",
          headers: {
            "Content-Type": "application/x-www-form-urlencoded",
          },
          body: `client_id=${
            microsoftConfig.clientId
          }&redirect_uri=${encodeURIComponent(
            microsoftConfig.redirectUri
          )}&grant_type=authorization_code&code=${code}&code_verifier=${
            authRequest.codeVerifier
          }&scope=${encodeURIComponent(
            "https://graph.microsoft.com/Calendars.ReadWrite offline_access"
          )}`,
        });

        console.log("Token response status:", tokenResponse.status);

        if (!tokenResponse.ok) {
          console.error("Token exchange failed:", await tokenResponse.text());
          return;
        }

        const tokenData = await tokenResponse.json();
        console.log("Token data received:", tokenData);

        if (tokenData?.id_token) {
          console.log("ID token received, updating user data...");
          await updateUserData({
            newUserData: { microsoftToken: tokenData.access_token },
          });
          console.log("User data updated successfully.");
        }
      } else {
        console.warn("Authentication was not successful:", authResult);
      }
    } catch (error) {
      console.error("Error during Microsoft sign-in:", error);
    }
  };

  const debouncedUpdateUserData = useCallback(
    debounce(async (color: string) => {
      try {
        await updateUserData({
          newUserData: {
            eventColor: color,
          },
        });
      } catch (error) {
        console.error("Failed to update color:", error);
        setSelectedColor(previousSelectedColor);
      }
    }, 500),
    []
  );

  const handleChangeColor = (color: string) => {
    setPreviousSelectedColor(selectedColor);
    setSelectedColor(color);
    debouncedUpdateUserData(color);
  };

  return (
    <ScrollView>
      <View marginH-30>
        <TouchableOpacity onPress={() => props.setSelectedPage(0)}>
          <View row marginT-20 marginB-35 centerV>
            <Ionicons
              name="chevron-back"
              size={14}
              color="#979797"
              style={{ paddingBottom: 3 }}
            />
            <Text
              style={{ fontFamily: "Poppins_400Regular", fontSize: 14.71 }}
              color="#979797"
            >
              Return to main settings
            </Text>
          </View>
        </TouchableOpacity>
        <Text style={styles.subTitle}>Calendar settings</Text>
        <View style={styles.card}>
          <Text style={styles.cardTitle} marginB-14>
            Event Color Preference
          </Text>
          <View row spread>
            <TouchableOpacity onPress={() => handleChangeColor(colorMap.pink)}>
              <View style={styles.colorBox} backgroundColor={colorMap.pink}>
                {selectedColor == colorMap.pink && (
                  <AntDesign name="check" size={30} color="white" />
                )}
              </View>
            </TouchableOpacity>
            <TouchableOpacity
              onPress={() => handleChangeColor(colorMap.orange)}
            >
              <View style={styles.colorBox} backgroundColor={colorMap.orange}>
                {selectedColor == colorMap.orange && (
                  <AntDesign name="check" size={30} color="white" />
                )}
              </View>
            </TouchableOpacity>
            <TouchableOpacity onPress={() => handleChangeColor(colorMap.green)}>
              <View style={styles.colorBox} backgroundColor={colorMap.green}>
                {selectedColor == colorMap.green && (
                  <AntDesign name="check" size={30} color="white" />
                )}
              </View>
            </TouchableOpacity>
            <TouchableOpacity onPress={() => handleChangeColor(colorMap.teal)}>
              <View style={styles.colorBox} backgroundColor={colorMap.teal}>
                {selectedColor == colorMap.teal && (
                  <AntDesign name="check" size={30} color="white" />
                )}
              </View>
            </TouchableOpacity>
            <TouchableOpacity
              onPress={() => handleChangeColor(colorMap.purple)}
            >
              <View style={styles.colorBox} backgroundColor={colorMap.purple}>
                {selectedColor == colorMap.purple && (
                  <AntDesign name="check" size={30} color="white" />
                )}
              </View>
            </TouchableOpacity>
          </View>
        </View>
        <View style={styles.card}>
          <Text style={styles.cardTitle}>Weekly Start Date</Text>
          <View row marginV-5 marginT-20>
            <Checkbox
              value={startDate}
              style={styles.checkbox}
              color="#ea156d"
              onValueChange={() => setStartDate(true)}
            />
            <View row marginL-8>
              <Text text70>Sundays</Text>
              <Text text70 color="gray">
                {" "}
                (default)
              </Text>
            </View>
          </View>
          <View row marginV-5>
            <Checkbox
              value={!startDate}
              style={styles.checkbox}
              color="#ea156d"
              onValueChange={() => setStartDate(false)}
            />
            <Text text70 marginL-8>
              Mondays
            </Text>
          </View>
        </View>
        <Text style={styles.subTitle} marginT-30 marginB-25>
          Add Calendar
        </Text>

        <Button
          onPress={() => promptAsync()}
          label="Connect Google"
          labelStyle={styles.addCalLbl}
          iconSource={() => (
            <View marginR-15>
              <GoogleIcon />
            </View>
          )}
          style={styles.addCalBtn}
          color="black"
          text70BL
        />
        <Button
          label="Connect Apple"
          labelStyle={styles.addCalLbl}
          iconSource={() => (
            <View marginR-15>
              <AppleIcon />
            </View>
          )}
          style={styles.addCalBtn}
          color="black"
          text70BL
        />
        <Button
          onPress={handleMicrosoftSignIn}
          label="Connect Outlook"
          labelStyle={styles.addCalLbl}
          iconSource={() => (
            <View marginR-15>
              <OutlookIcon />
            </View>
          )}
          style={styles.addCalBtn}
          color="black"
          text70BL
        />

        <Text style={styles.subTitle} marginT-30 marginB-20>
          Connected Calendars
        </Text>
        <View style={styles.card}>
          <View style={{ marginTop: 20 }}>
            <Button
              onPress={fetchAndSaveGoogleEvents}
              label="Sync Google"
              labelStyle={styles.addCalLbl}
              iconSource={() => (
                <View marginR-15>
                  <GoogleIcon />
                </View>
              )}
              style={styles.addCalBtn}
              color="black"
              text70BL
            />
            <Button
              onPress={fetchAndSaveMicrosoftEvents}
              label="Sync Outlook"
              labelStyle={styles.addCalLbl}
              iconSource={() => (
                <View marginR-15>
                  <OutlookIcon />
                </View>
              )}
              style={styles.addCalBtn}
              color="black"
              text70BL
            />
          </View>
        </View>
      </View>
    </ScrollView>
  );
};

const styles = StyleSheet.create({
  addCalBtn: {
    backgroundColor: "#ffffff",
    marginBottom: 15,
    justifyContent: "flex-start",
    paddingLeft: 25,
  },
  backBtn: {
    backgroundColor: "red",
    marginLeft: -2,
    justifyContent: "flex-start",
  },
  card: {
    backgroundColor: "white",
    width: "100%",
    padding: 20,
    paddingBottom: 30,
    marginTop: 20,
    borderRadius: 12,
  },
  colorBox: {
    aspectRatio: 1,
    justifyContent: "center",
    alignItems: "center",
    width: 51,
    borderRadius: 12,
  },
  checkbox: {
    borderRadius: 50,
  },
  addCalLbl: {
    fontSize: 16,
    fontFamily: "PlusJakartaSan_500Medium",
  },
  subTitle: {
    fontFamily: "Manrope_600SemiBold",
    fontSize: 18,
  },
  cardTitle: {
    fontFamily: "Manrope_500Medium",
    fontSize: 15,
  },
});

export default CalendarSettingsPage;
