import React from "react";


import FirebaseUtils from './../utils/firebase.utils';

import { message } from 'antd';

import { Link } from 'react-router-dom';

import GenericAdd from './../../lib/modules/generic/generic-add/generic-add';

import GenericList from './../../lib/modules/generic/generic-list/generic-list';

import GenericEdit from './../../lib/modules/generic/generic-edit/generic-edit';

import GenericDetail from './../../lib/modules/generic/generic-detail/generic-detail';

import GenericUpload from './../../lib/modules/generic/generic-upload/generic-upload';

import DateUtils from '../utils/date/date.utils';

import { Users } from './';

import ApiUtils from '../utils/api/api.utils';

import { Timestamp } from 'firebase/firestore';

const moment = require('moment-timezone');

let cityKey = {
    kozhikode: 'KL305',
    kannur: 'KL306',
    malappuram: 'KL307',
};

class Base {

    id;
    name;
    endpoint;
    pluralName;
    schema;
    fields;
    listFields;
    filterFields;

    // columns = [];

    constructor(fields = []) {
        this.endpoint = this.getEndpoint;


        this.name = this.getName;

        this.fields = fields;

        // this.columns = [];
    }

    disableAddModal() {
        return false;
    }

    disableDelete() {
        return false;
    }

    disableEdit() {
        return false;
    }

    // get columns() {
    //     return [];
    // }

    filterDate() {
        return false;
    }



    /**
     *
     * @param {*} queries
     * @returns
     */
    // getAll()

    getAll(queries = [], model) {
        let all = [];

        var content = {};

        var locations = ['kozhikode', 'malappuram', 'kannur'];

        var locationPromise = (locations) => {

            return this.getCity(queries, locations).then((result) => {
                //get records from getCity
                all = [].concat(...all, ...result[model]);
                content[locations] = result;
                return content;
            });
        };

        return new Promise((resolve) => {
            Promise.all(locations.map((location) => locationPromise(location))).then((result) => {
                resolve({ all, content });
            });
        });
    }


    /*
    * @param {*} queries
    * @returns
    */
    getCity(queries, city) {

        var q = [].concat(queries)

        var baseQueries = [
            {
                field: 'dealerCode',
                value: cityKey[city],
            },
        ];

        if (queries.length) {
            q.push(baseQueries[0]);
        }


        return this.get(q, city)
    }



    /**
     * Get the data from the table
     */
    getData(path, queries = []) {
        // Get the records from firebase
        return FirebaseUtils.get(path, queries, this);
    }

    getFireStoreApp() {
        return FirebaseUtils.getFireStoreApp();
    }

    firebase() {
        return FirebaseUtils.getFirebaseObject();
    }

    getUser() {
        return FirebaseUtils.getUser();
    }


    getToken() {
        return FirebaseUtils.getToken();
    }

    /**
     * 
     * @returns 
     */
    getDefaultColumns(step) {

        let columns = this.columns.map((column) => {

            return {
                // dataIndex: `${this.modelName}.${record.field}`,
                title: `${column.caption}`,
                key: `${column.key}`,
                render: (record) => {

                    let index = `${this.modelName}.${column.field}`

                    return record[this.modelName][column.field];

                }
            }
        });

        columns.push({
            title: `Action`,
            key: 999,
            render: (record) => {

                // let index = `${this.modelName}.${column.field}`

                return <Link className="" to={`/task/${step.id}?record_id=${record['record_id']}&process_transaction_id=${record.id}`}>
                    View
                </Link>;

            }
        })


        return columns;
    }

    getCreation(field = 'created') {

        var user = FirebaseUtils.getUser();

        var creation = DateUtils.getCreation(field)

        return {
            ...creation,
            [field + '_by_name']: user.name,
            [field + '_by']: user.id,
        }
    }

    /**
     * Get the queries including url params 
     */
    getQueries = (queries, urlParams) => {

        Object.keys(urlParams).forEach((key) => {

            queries.push({
                field: key,
                value: urlParams[key]
            })
        });

        return queries;
    }


    /**
     * Get the data from the table
     */
    get(queries = [], config = {
        // limit: 20
    }) {

        queries.push({
            field: 'deleted_at',
            operator: '==',
            value: null
        })

        // console.log("Calling", this.name, 'with', queries);

        // Get the records from firebase
        return FirebaseUtils.getRecords(queries, this, config).then((result) => {

            // For each record find creator
            return Promise.all(result[this.name].map(this.getCreator)).then((result) => {

                return {
                    [this.name]: result
                }
            })
        });
    }

    /**
     * Get who created the record
     */
    getCreator = (record) => {

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

            if (record.created_by) {

                if (typeof record.created_by === 'string') {

                    Users.getRecord(record.created_by).then((result) => {

                        resolve({
                            ...record,
                            created_by: result
                        })
                    })

                } else {

                    Users.getRecord(record.created_by.id).then((result) => {

                        resolve({
                            ...record,
                            created_by: result
                        })
                    })
                }

            } else {

                resolve({
                    ...record
                })

            }
        })
    }

    /**
     * Get the data from the table
     */
    getMethod(queries = [], config = {}) {

        queries.push({
            field: 'deleted_at',
            operator: '==',
            value: null
        })

        // Get the records from firebase
        return FirebaseUtils.getRecords(queries, this, config);
    }


    listenRecord(id, callback) {
        return FirebaseUtils.listenRecord(id, this, callback);
    }

    /**
     * 
     * @param {*} id 
     * @returns 
     */
    getRecordReference = (id = null) => {

        return FirebaseUtils.getRecordReference(this, id);
    }


    /**
     *
     * @param {*} values
     * @returns
     */
    getRecord = (id) => {
        return FirebaseUtils.getRecord(id, this);
    };

    /**
     *
     * @param {*} values
     * @param {*} user
     * @returns
     */
    add = (values, config = { hideAlert: false, avoidTimeRecording: false }) => {

        console.log(this.name, ' Addition started', values)

        var user = FirebaseUtils.getUser();

        let creation = {
            created_by: user.id,
            // These columns will help 
            deleted_at: null,
            deleted_by: null,
        };

        // In some cases we records the following datas during function call(in such cases the default value of  avoidTimeRecording will be choosen)
        // In other cases ie, when avoidTimeRecording is true the following records will be created when a new record is added.

        // When adding a new record
        if (!avoidTimeRecording) {

            creation = {
                recorded_at: admin.firestore.FieldValue.serverTimestamp(),
                created_at: moment().format('DD/MM/YYYY HH:mm'),
                created_date: moment().startOf('day').valueOf(),
                created_time: moment().valueOf(),
            };
        }

        this.cleanParams(values);

        let params = {
            ...values,
            ...creation,
            ...this.extraParams()
        };

        // Get the records from firebase
        return FirebaseUtils.addRecord(this.name, params).then((result) => {

            if (!config.hideAlert) {

                message.success('New record added');
            }

            console.log(this.name, ' Addition completed', result.id)

            return result;
        });
    };

    /**
     * Using a batch add the record 
     */
    addBatch = async (batch, values, config) => {

        const reference = await this.getRecordReference();

        await batch.set(reference, this.appendDefaultValues(values))

        return {
            id: reference.id
        }
    }



    /**
     * Append the default values that would be added for each record
     * 
     * @param {*} values 
     * @returns 
     */
    appendDefaultValues = (values) => {

        var user = FirebaseUtils.getUser();

        let creation = {

            recorded_at: Timestamp.fromDate(new Date()),

            created_at: moment().format('DD/MM/YYYY HH:mm'),
            created_date: moment().startOf('day').valueOf(),
            created_time: moment().valueOf(),
            created_by: user.id,

            // These columns will help 
            deleted_at: null,
            deleted_by: null,
        };

        this.cleanParams(values);

        return {
            ...values,
            ...creation
        }

    }


    /**
     * Make an post call to the endpoint with params 
     * 
     * @param {*} param0 
     */
    addHttp = ({ url, formBody }) => {

        return ApiUtils.post({ url: url, formBody })

    }

    //Add document of uploaded time
    addUploadsDetails = (user) => {

        return FirebaseUtils.addUploadsDetails(user, this.name);
    };

    /**
   *
   * @param {*} values
   * @param {*} user
   * @returns
   */
    addDocument = (id, values) => {

        let params = {
            ...this.appendDefaultValues(values),
            ...this.extraParams()
        };

        this.cleanParams(params);

        // Get the records from firebase
        return FirebaseUtils.addDocument(id, this.name, params).then((result) => {

            message.success(`New ${this.name} created`);

            return result;
        });
    };

    /**
     * Update of model
     *
     * @param {*} id
     * @param {*} values
     * @param {*} user
     * @returns
     */
    update = (id, values, config = { hideAlert: false }) => {

        var user = FirebaseUtils.getUser();

        let creation = {
            updated_at: moment().format('DD/MM/YYYY HH:mm'),
            updated_date: moment().startOf('day').valueOf(),
            updated_time: moment().valueOf(),
            updated_by: user.id,
        };

        this.cleanParams(values);

        let params = {
            ...values,
            ...creation,
        };

        // Get the records from firebase
        return FirebaseUtils.updateRecord(this.name, id, params).then((result) => {

            if (!config.hideAlert) {

                message.success(`${this.name} has been updated`);
            }

            return result;
        });
    };

    /**
     * Delete a model
     *
     * @param {*} id
     * @param {*} values
     * @param {*} user
     * @returns
     */
    delete = (id, config = { hideAlert: false }) => {

        // Get the records from firebase
        return FirebaseUtils.deleteRecord(this.name, id).then((result) => {

            if (!config.hideAlert) {

                message.success('Record deleted');
            }

            return result;
        });
    };

    /**
     * Upload the file to storage and return url
     * 
     * @param {*} file 
     */
    uploadBase64 = (file) => {

        var random = {
            customerName: 'CustomerDocument' + Math.round(Math.random() * 1000000)
        }

        return FirebaseUtils.uploadBase64(file, random, '/collections').then((result) => {

            let file = {
                uid: random.customerName,
                name: random.customerName,
                status: 'done',
                url: result.url,
                type: result.meta.contentType
            }

            console.log(file);

            return file;

        });
    }


    //  * Base Function to access any custom firebase function
    //  * 
    //  * @param {*} endpoint 
    //  * @param {*} formBody 
    //  * @returns 
    //  */
    loadFunction = (endpoint, formBody) => {

        var firebase = FirebaseUtils.getFirebaseObject();

        var callableFunction = firebase.functions().httpsCallable(endpoint);
        console.log({ formBody })

        return callableFunction(formBody).then(function (result) {
            return result.data;
        });
    }

    /**
     * To be used at any place to order any data
     * by a field
     * 
     * @param {*} arr 
     * @param {*} field 
     * @returns 
     */
    orderArray = (arr, field) => {

        return arr.sort((a, b) => {

            return a[field] - b[field]

            // if (a[field] > b[field]) {
            //     return -1;
            // }
            // if (a[field] > b[field]) {
            //     return 1;
            // }
            // // a must be equal to b
            // return 0;
        })
    }

    /**
     * Group the array by key
     * 
     * @param {*} xs 
     * @param {*} key 
     * @returns 
     */
    groupBy = (xs, key) => {

        return xs.reduce(function (rv, x) {
            (rv[x[key]] = rv[x[key]] || []).push(x);

            return rv;
        }, {});
    };


    /**
     * Clean the params 
     * 
     * @param {*} values 
     * @returns 
     */
    cleanParams = (values) => {

        // 
        Object.keys(values).forEach((key) => {

            if (values[key] === undefined) {

                values[key] = null
            }
        })

        return values;
    }


    //Get Records with a limit 
    getOrderRecord = (location, queries, config) => {

        queries.push({
            field: 'deleted_at',
            operator: '==',
            value: null
        })
        return FirebaseUtils.getOrderRecord(location, queries, this, config)
    }

    //Get Records with a filter 
    getUpdateFilter = (location, queries, config = []) => {

        return FirebaseUtils.getOrderRecord(location, queries, this, config)

    }


    extraParams = () => {

        return {}
    }

    columns() {

        return [
            {
                caption: 'Staff',
                field: 'staff.name',
                key: 'staff',
            },
            {
                caption: 'Weight',
                field: 'weight',
                key: 'weight',
            },
            {
                caption: 'Date',
                field: 'created_at',
                key: 'created_at',
            },
        ];
    }

    AddComponent = GenericAdd;

    ListComponent = GenericList;

    EditComponent = GenericEdit;

    DetailComponent = GenericDetail;

    UploadComponent = GenericUpload;

    ModalAddComponent = GenericAdd;
}

export default Base;
