import React, { createContext, useContext, useState, useEffect } from 'react';
import axios from 'axios';
import { SettingsContext } from './SettingsProvider';
import { format } from 'date-fns';
import Settings from './screens/Settings';
import { ThemeButton, ThemeText } from './common/ThemeTypes';
import { StyleSheet, Text, View } from 'react-native';
import { useColors } from './common/colors';
import {decode as atob, encode as btoa} from 'base-64'
import Login from './screens/Login';

let errorObject;
export const InterfaceContext = createContext<any>(null);

const Interface = ({ children }) => {
    const colors = useColors();
    const { settings } = useContext(SettingsContext);
    const [userInformation, setUserInformation] = useState(null);
    const [baseData, setBaseData] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(false);

    const fetchData = async () => {
        try {
            if (!settings.url) throw new InterfaceError("Invalid URL")
            const userinformation = await fetchUserInformation(settings.username);
            const basedata = await fetchBaseData();
            setUserInformation(userinformation)
            setBaseData(basedata)
            if (!userinformation || !basedata) throw new InterfaceError("Data returned is Null");
            setError(false)
        } catch (error) {
            console.error(error);
            errorObject = error;
            setError(true)
        } finally {
            setLoading(false)
        }
    }

    useEffect(() => {
        fetchData();
    }, [settings]);

    const refresh = () => {
        fetchData();
    };

    const axiosInstance = axios.create({
        baseURL: settings.url,
    });

    axiosInstance.interceptors.request.use(
        (config) => {
            if (!settings.url) {
                throw new InterfaceError("Invalid URL")
            }
            if (settings.requireAuth) {
                const { username, password } = settings;
                const token = btoa(`${username}:${password}`);
                config.headers.Authorization = `Basic ${token}`;
            }

            return config;
        },
        (error) => Promise.reject(error)
    );

    const fetchBaseData = async () => {
            return await requestGet('basedata/');
    };
    
    const fetchUserInformation = async (username) => {
            const userinformation = await requestGet(`userinformation/?username=${username}`, false);
            if (!userinformation) {
                return await requestGet(`demoinformation/`);
            }
            return userinformation;
    };
    
    const fetchTimes = async () => {
            return await requestGet('hours/');
    };
    
    const fetchScheduleByWeek = async (type, value, group, week, year) => {
            const groupparam = type === 'class' && group ? `&group=${group}` : '';
            return await requestGet(`schedule/week/?type=${type}&value=${value}${groupparam}&week=${week}&year=${year}`);
    };
    
    const fetchScheduleByDate = async (type, value, group, date) => {
            const groupparam = type === 'class' ? `&group=${group}` : '';
            return await requestGet(`schedule/date/?type=${type}&value=${value}${groupparam}&date=${format(date, 'yyyy-MM-dd')}`);
    };
    
    const fetchAppointments = async (date) => {
            return await requestGet(`appointments/?date=${format(date, 'yyyy-MM-dd')}`);
    };
    
    const fetchTests = async (type, value, date) => {
            return await requestGet(`tests/?type=${type}&value=${value}&date=${format(date, 'yyyy-MM-dd')}`);
    };
    
    const fetchDayTypes = async (from, until) => {
            return await requestGet(`daytypes/?from=${format(from, 'yyyy-MM-dd')}&until=${format(until, 'yyyy-MM-dd')}`);
    };
    
    const fetchFreeRooms = async (date, from, until) => {
            return await requestGet(`freerooms/?date=${format(date, 'yyyy-MM-dd')}&from=${from}&until=${until}`);
    };
    

    const requestGet = async (url, handleError = true) => {
        try {
            const response = await axiosInstance.get(url);
            if (response.status === 200 && response.data.success === true) {
                return response.data.data;
            } else {
                throw new InterfaceError(response.data.message);
            }
        } catch (error) {
            if (!handleError) {
                return null
            }else if (error.response) {
                if (error.response.data.message){
                    throw new InterfaceError(error.response.status + ": " + error.response.data.message);
                }else if (error.response.status === 404) {
                    throw new InterfaceError('404: URL wurde auf dem Server nicht gefunden');
                } else if (error.response.status === 500) {
                    throw new InterfaceError('500: Ein unbekannter Fehler ist auf dem Webservice aufgetreten');
                } else if (error.response.status === 502) {
                    throw new InterfaceError('502: Webservice ist unerreichbar');
                }
                throw new Error(`${error.response.status}: Ein fehler ist auf dem Server aufgetreten`);
            } else if (error.request) {
                throw new InterfaceError('Netzwerkfehler');
            } else {
                throw new InterfaceError(error.message || 'Ein unbekannter fehler ist aufgetreten');
            }
        }
    };
    


    const styles = StyleSheet.create({
        container: {
            paddingTop: 30,
            flex: 1,
            backgroundColor: colors.backSecondary,
        },
        titleBox: {
            paddingHorizontal: 20,
            paddingVertical: 10,
        },
        title: {
            fontSize: 20,
            fontWeight: 'bold',
        },
        button: {
            marginTop: 5,
        }
    })

    const renderContent = () => {
        if (error) return (
            <View style={styles.container}>
                <View style={styles.titleBox}>
                    <ThemeText style={styles.title}>Fehler beim laden der Daten</ThemeText>
                    <ThemeText>{errorObject?.message}</ThemeText>
                    <ThemeButton style={styles.button} onPress={refresh}><Text>Neu Versuchen</Text></ThemeButton>
                </View>
                <Login />
            </View>
        )
        if (!loading) return (children)
        //return (children)
    }

    return (
        <InterfaceContext.Provider value={{ userInformation, baseData, refreshInterface: refresh, fetchBaseData, fetchTimes, fetchScheduleByWeek, fetchScheduleByDate, fetchAppointments, fetchTests, fetchDayTypes, fetchFreeRooms }}>
            {renderContent()}
        </InterfaceContext.Provider>
    );
};

export default Interface;

export class InterfaceError extends Error {
    constructor(message) {
        super(message);
        this.name = "InterfaceError";
    }
}