import React, { useState, useEffect, useContext } from 'react';

import firebase from 'firebase/compat/app';


// import 'firebase/compat/firestore';
// import 'firebase/compat/auth';

import 'firebase/compat/database'; // If using Firebase database
import 'firebase/compat/firestore'; // If using Firebase database
import 'firebase/compat/auth'; // If using Firebase database
import 'firebase/compat/storage'; // If using storage
import 'firebase/compat/functions';


// Add the Performance Monitoring library
import 'firebase/compat/performance';

import moment from 'moment';

import { SmileOutlined } from '@ant-design/icons';

import { message, notification, Button } from 'antd';

import { Users, Roles } from './../models/';

// import 'firebase/storage';

// Get a reference to the database service
// var database = firebase.database();

var firebaseConfig = {
    apiKey: process.env.REACT_APP_apiKey,
    authDomain: process.env.REACT_APP_authDomain,
    databaseURL: process.env.REACT_APP_databaseURL,
    projectId: process.env.REACT_APP_projectId,
    storageBucket: process.env.REACT_APP_storageBucket,
    messagingSenderId: process.env.REACT_APP_messagingSenderId,
    appId: process.env.REACT_APP_appId,
    measurementId: process.env.REACT_APP_measurementId,
};

// This shouldnt come here ideally , 
// #note Only a temporary object maintained for kia
let cityKey = {
    kozhikode: 'KL305',
    kannur: 'KL306',
    malappuram: 'KL307',
};


// console.log(firebaseConfig);

var app = {};

var storage = {};

var user = {};

var functions = {};

var database = {};

let firstTime = true;

export default class FirebaseUtils {

    static connect = () => {

        return new Promise((resolve, reject) => {

            if (!firebase.apps.length) {

                // Initialize the application
                firebase.initializeApp(firebaseConfig);
            } else {
                firebase.app(); // if already initialized, use that one
            }

            storage = firebase.storage();

            database = firebase.database();

            var starCountRef = firebase.database().ref('version');

            starCountRef.on('value', (result) => {

                // console.log(result.data());

                const btn = (
                    <Button
                        type="primary"
                        size="small"
                        onClick={() => {
                            window.location.reload(true);
                        }}
                    >
                        Reload
                    </Button>
                );

                // if (!firstTime) {
                //     notification.open({
                //         message: 'Hello there,',
                //         btn,
                //         onClose: () => {
                //             window.location.reload(true);
                //         },
                //         description:
                //             'We have released an update to the application. Browser would reload the application to fetch the latest updates. Thank you.',
                //         icon: <SmileOutlined style={{ color: '#108ee9' }} />,
                //     });
                // } else {
                //     firstTime = false;
                // }
            });

            app = firebase.firestore();

            // Initialize Performance Monitoring and get a reference to the service
            const perf = firebase.performance();

            // storage = firebase.storage();

            // firebase.firestore.setLogLevel("debug");
            // if (window.location.hostname === "localhost") {
            //     app.useEmulator("localhost", 5005);
            // }

            // Initialize Cloud Functions through Firebase
            // functions = firebase.functions();

            // if (process.env.NODE_ENV === 'development') {

            //     functions.useEmulator("localhost", 5001);
            // }

            resolve(app, database);
        });
    };

    static onVersionUpdate = (callback) => {
        var starCountRef = firebase.database().ref('version');

        starCountRef.on('child_changed', callback);
    };

    static getFirebaseObject = () => {
        return firebase;
    };

    static getFireStoreApp = () => {
        return app;
    };


    static getUser = () => {
        return user || {};
    };

    static getUserInfo = (uid) => {
        return app
            .collection('users')
            .doc(uid)
            .get()
            .then((result) => {

                // User data
                user = {
                    ...result.data(),
                    id: result.id
                };

                return result;
            });
    };

    static updateProfile = (uid, params) => {
        return app.collection('users').doc(uid).update(params);
    };

    static getAuthStatus = () => {
        return new Promise((resolve, reject) => {
            return firebase.auth().onAuthStateChanged((user) => {

                if (user) {

                    return this.getUserDetail(user.uid).then((result) => {

                        resolve(result);

                    })

                    // return Users.getRecord(user.uid).then((result) => {

                    //     return Roles.getRecord(result.role).then((role) => {

                    //         var data = {
                    //             ...result,
                    //             role: role
                    //         }

                    //         resolve(data);

                    //     })
                    // })

                } else {
                    resolve(true);
                }
            });
        });
    };

    /**
     * Get User detail
     * 
     * @param {*} uid 
     * @returns 
     */
    static getUserDetail = (uid) => {

        return Users.getRecord(uid).then((result) => {

            return Roles.getRecord(result.role_id).then((role) => {

                var data = {
                    ...result,
                    role: role
                }

                // Update file local data
                user = data;

                return data;

            })
        })


    }

    /**
     * 
     * 
     * @returns 
     */
    static loginWithPhone = () => {

        return new Promise((resolve, reject) => {
            // firebase.auth().settings.appVerificationDisabledForTesting = true;

            var appVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');

            var phoneNumber = '+917899205111';

            // var appVerifier = response;

            firebase
                .auth()
                .signInWithPhoneNumber(phoneNumber, appVerifier)
                .then(function (confirmationResult) {
                    resolve(confirmationResult);
                })
                .catch(function (error) {
                    console.log(error);
                });

            // var recaptcha = new firebase.auth.RecaptchaVerifier('recaptcha-container', {
            //     'size': 'invisible',
            //     'callback': function (response) {

            //         var appVerifier = response;

            //         firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
            //             .then(function (confirmationResult) {

            //                 console.log(confirmationResult);

            //                 resolve(confirmationResult);

            //             }).catch(function (error) {

            //                 console.log(error);
            //             });

            //     }
            // });
        });
    };

    static loginWithEmail = ({ email, password }) => {
        // var email = '32teeths@gmail.com';
        // var password = '123456';

        return firebase
            .auth()
            .signInWithEmailAndPassword(email, password)
            .catch(function (error) {
                // Handle Errors here.
                var errorCode = error.code;
                var errorMessage = error.message;

                console.log(errorCode, errorMessage);
            })
            .then((result) => {
                return this.getUserDetail(result.user.uid);
                // return FirebaseUtils.getUserInfo(result.user.uid);
            });
    };

    static getToken = () => {
        return firebase
            .auth()
            .currentUser.getIdToken(true)
            .then(function (idToken) {
                return idToken;
            })
            .catch(function (error) {
                return '';
            });
    };

    static changePassword = (details) => {
        var user = firebase.auth().currentUser;

        var newPassword = details.npassword;

        return user.updatePassword(newPassword);
    };

    // For EDP Ends

    // Admin Users
    static getUsers = () => {
        let content = {};

        return new Promise((resolve, reject) => {
            app.collection('users')
                .get()
                .then((querySnapshot) => {
                    querySnapshot.forEach(function (doc) {
                        content[doc.id] = doc.data();
                    });

                    resolve(content);
                });
        });
    };

    // For Stock Transfer Ends

    // User Authentication

    static createUser = ({ email, password }) => {
        var createUser = firebase.functions().httpsCallable('createUser');

        return createUser({ email, password }).then(function (result) {
            console.log(result);

            return { user: result.data.uid };
        });
    };

    static addUserInfo = (id, values) => {
        return app
            .collection('users')
            .doc(id)
            .set({
                ...values,
                created_at: moment().format('DD/MM/YYYY HH:mm'),
            });
    };

    static updateUserInfo = (id, values) => {
        return app
            .collection('users')
            .doc(id)
            .update({
                ...values,
                updated_at: moment().format('DD/MM/YYYY HH:mm'),
            });
    };

    /**
     * Get Base Records
     *
     * @param {*} queries
     * @param {*} model
     * @returns
     */
    static get = (path, queries = []) => {
        // Base structure
        let content = { [path]: [] };

        return new Promise((resolve, reject) => {
            var ref = app.collection(path);

            queries.forEach((query) => {
                ref = ref.where(query.field, query.operator || '==', query.value);
            });

            ref.get().then((querySnapshot) => {
                querySnapshot.forEach(function (doc) {
                    content[path].push({
                        ...doc.data(),
                        id: doc.id,
                    });
                });

                resolve(content);
            });
        });
    };



    /**
     * The old get records functions 
     * 
     * @param {*} city 
     * @param {*} queries 
     * @param {*} model 
     * @returns 
     */
    static getRecordsLegacy = (city, queries = [], model) => {
        // Base structure
        let content = { [model]: [] };

        return new Promise((resolve, reject) => {
            var ref = app.collection(model);

            queries.forEach((query) => {
                ref = ref.where(query.field, query.operator || '==', query.value);
            });

            if (city) {
                ref = ref.where('dealerCode', '==', cityKey[city]);
            }

            ref.get().then((querySnapshot) => {
                querySnapshot.forEach(function (doc) {
                    content[model].push({
                        ...doc.data(),
                        id: doc.id,
                    });
                });

                resolve(content);
            });
        });
    };


    /**
     * Get Base Records
     *
     * @param {*} queries
     * @param {*} model
     * @returns
     */
    static getRecords = (queries = [], model, config = {
        // limit: 20
    }) => {
        // Base structure
        let content = { [model.endpoint]: [] };

        return new Promise((resolve, reject) => {
            var ref = app.collection(model.endpoint);

            queries.forEach((query) => {
                ref = ref.where(query.field, query.operator || '==', query.value);
            });

            if (config.orderBy) {
                ref = ref.orderBy(config.orderBy, config.order);
            }

            // If there is a start at field
            // Append a value
            if (config.startAt) {
                ref = ref.startAt(config.startAt);
            }

            if (config.limit) {
                ref = ref.limit(config.limit)
            }

            ref.get().then((querySnapshot) => {
                querySnapshot.forEach(function (doc) {
                    content[model.name].push({
                        ...doc.data(),
                        id: doc.id,
                    });
                });

                resolve(content);
            });
        });
    };

     /**
     * Generic method to write listing
     */
      static writeListing = (user, records, model) => {
        var batch = app.batch()

        Object.keys(records).forEach(async (key) => {
            var docRef = app.collection(model).doc(key);

            await batch.set(docRef, records[key], { merge: true });
        });
        

        // var timeRef = app
        //     .collection('uploads')
        //     .doc('lastUpdated');

        // batch.set(timeRef, { timestamp: moment().format('DD/MM/YYYY HH:mm') });
        return this.addUploadsDetails(user, model).then(() => {
            return batch.commit();
        });
    };

    static addUploadsDetails = (user, model) => {
        let body = {
            model: model,
            created_by: {
                name: user.name,
                role: user.role.name,
            },
            created_at: moment().format('DD/MM/YYYY HH:mm'),
            created_time: moment().valueOf(),
            deleted_by:null,
            deleted_at:null
        };
        return app.collection('uploads').add(body);
    };


    
    //Get data with a limit and orderBy
    static getOrderRecord = (city, queries , model, config = {}) => {

        let start = null;

        let end = null;

        // Base structure
        let content = { [model.endpoint]: [] };

        return new Promise((resolve, reject) => {
            var ref = app.collection(model.endpoint);

            queries.forEach((query) => {
                ref = ref.where(query.field, query.operator || '==', query.value);
            });

            // if (city) {
            //     ref = ref.where('dealerCode', '==', cityKey[city]);
            // }

          

            if (config.orderBy && !config.direction) {
                ref = ref.orderBy(config.orderBy);
            }

            if (config.orderBy && config.direction) {
                ref = ref.orderBy(config.orderBy, config.direction);
            }

            if (config.end) {
                ref = ref.startAfter(config.end);
            }

            // If there is a start at field
            // Append a value
            if (config.startAt) {
                ref = ref.startAt(config.startAt);
            }

            if (config.limit) {
                ref = ref.limit(config.limit)
            }


            ref.get().then((querySnapshot) => {

                // console.log(querySnapshot)

                start = querySnapshot.docs[0];

                end = querySnapshot.docs[querySnapshot.docs.length - 1];


                querySnapshot.forEach(function (doc) {
                    //console.log(doc.data())
                    content[model.name].push({
                        ...doc.data(),
                        id: doc.id,
                      
                    });
                });
                content.start = start
                content.end = end


                resolve(content);
            });
        });
    };


    /**
     * Function Pushs a new record to the model
     *
     * @param {*} city
     * @param {*} model
     * @param {*} values
     */
    static addRecord = (model, values) => {
        return app.collection(model).add(values);
    };

    /**
     * Function Adds a new record to the model
     *
     * @param {*} city
     * @param {*} model
     * @param {*} values
     */
    static addDocument = (id, model, values) => {
        return app.collection(model).doc(id).set(values);
    };

    /**
     * Get the Record
     *
     * @param {*} id
     * @param {*} model
     * @returns
     */
    static listenRecord = (id, model, callback) => {
        return app
            .collection(model.name)
            .doc(id)
            .onSnapshot((result) => {

                return callback({
                    ...result.data(),
                    id: result.id,
                })

            })
    };

    /**
     * Get the Record Reference
     *
     * @param {*} id
     * @param {*} model
     * @returns
     */
    static getRecordReference = (model, id = null) => {

        if (id) {
            return app
                .collection(model.name)
                .doc(id);
        } else {
            return app
                .collection(model.name)
                .doc();
        }
    };

    /**
     * Get the Record
     *
     * @param {*} id
     * @param {*} model
     * @returns
     */
    static getRecord = (id, model) => {
        return app
            .collection(model.name)
            .doc(id)
            .get()
            .then((result) => {
                return {
                    ...result.data(),
                    id: result.id,
                };
            });
    };

    /**
     *
     */
    static updateRecord = (model, id, values) => {
        return app.collection(model).doc(id).update(values);
    };

    static deleteRecord = (model, id) => {

        var user = this.getUser();

        var params = {
            deleted_at: moment().valueOf(),
            deleted_by: user.id
        }

        return app.collection(model).doc(id).update(params);
    };

    //Cart Section Ends
    static logout = () => {
        return firebase.auth().signOut();
    };


    /**
    * Upload the file to storage
    */
    static uploadAttachment = (files, customer, index) => {
        var hide;

        // var url = index + customer.customerName + '-' + +new Date();

        var url = index + customer.customerName + files.name;

        var ref = storage.ref(url);

        var uploadTask = ref.put(files);

        uploadTask.on('state_changed', (snapshot) => {
            var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;

            // console.log('Upload is ' + progress + '% done');

            // console.log(snapshot.state);

            if (progress >= 100) {
                hide && hide();

                message.success(`Upload Complete.`);
            } else {
                // hide = message.loading(`Uploading...`, 1);
            }
        });

        return uploadTask.then((snapshot) => {
            return ref.getMetadata().then((result) => {
                return snapshot.ref.getDownloadURL().then((downloadUrl) => {
                    let meta = { contentType: result.contentType };

                    return { url: downloadUrl, meta: meta };
                });
            });
        });
    };

    /**
     * Upload the Base64 to storage
     */
    static uploadBase64 = (files, index) => {

        var hide;

        var url = index + files.name + '-' + (+new Date());

        var ref = storage.ref(url);

        var uploadTask = ref.putString(files, 'data_url', { contentType: 'image/jpg' });

        uploadTask.on('state_changed', (snapshot) => {

            // Progress
            var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;

            // console.log('Upload is ' + progress + '% done');

            // console.log(snapshot.state);

            if (progress >= 100) {
                hide && hide();

                message.success(`Upload Complete.`);
            } else {
                // hide = message.loading(`Uploading...`, 1);
            }
        });

        return uploadTask.then((snapshot) => {
            return ref.getMetadata().then((result) => {
                return snapshot.ref.getDownloadURL().then((downloadUrl) => {
                    let meta = { contentType: result.contentType };

                    return { url: downloadUrl, meta: meta };
                });
            });
        });
    };

}


