import { Component, OnInit, ViewContainerRef } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ModalDialogOptions, ModalDialogService, RouterExtensions } from '@nativescript/angular';
import { encoding, Folder, knownFolders } from '@nativescript/core';
import { Select, Store } from '@ngxs/store';
import * as TNSEmail from 'nativescript-email';
import { FeedbackType } from 'nativescript-feedback';
import * as TNSPhone from 'nativescript-phone';
import { Observable } from 'rxjs';
import { withLatestFrom } from 'rxjs/operators';
import { feedbackMessage } from '~/pages/material/utils/feedback-messages';
import { ExportTableData } from '../../entities/export-table-data';
import { LoadEmails, LoadExportPerson, LoadExportPersonView, LoadPhoneNumbers } from '../../state-mgmt/export.actions';
import { ExportState } from '../../state-mgmt/export.state';

import * as base64 from 'base-64';
import * as Permissions from 'nativescript-permissions';
import { isAndroid } from 'nativescript-platform';
import { ModalWarningComponent } from '../../components/modal-view-warning/modal-view-warning.component';
import { ExportPersonResult } from '../../entities/output/exportPersonResult';

declare var android;

@Component({
    selector: 'Export',
    moduleId: module.id,
    templateUrl: './export.component.html',
    styleUrls: ['./_export.component.scss']
})

export class ExportComponent implements OnInit {
    @Select(ExportState.getExportTableData) exportTableData$: Observable<ExportTableData>;
    @Select(ExportState.getPhoneNumbers) phoneNumbers$: Observable<Object>;
    @Select(ExportState.getEmails) emails$: Observable<Object>;
    @Select(ExportState.getExportPerson) exportPerson$: Observable<[ExportPersonResult]>;
    @Select(ExportState.isLoading) isLoading$: Observable<boolean>;

    templateId: number = null;
    selected: boolean[] = [];
    massAction: boolean;
    allSelected: boolean = false;

    constructor(
        private store: Store,
        private routerExtensions: RouterExtensions,
        private route: ActivatedRoute,
        private viewContainerRef: ViewContainerRef,
        private modalService: ModalDialogService
    ) {}

    async ngOnInit() {
        this.massAction = false;
        this.templateId = +this.route.snapshot.params['idTemplate'];
        this.store.dispatch(new LoadExportPersonView(this.templateId))
            .pipe(withLatestFrom(this.exportTableData$))
            .subscribe(([_, output]) => {
                output.ids.forEach(a => this.selected.push(false));
            }, err => {
                console.log(err);
                feedbackMessage(FeedbackType.Error, 'Načítání dat', `Při načítání dat došlo k chybě. Zkontrolujte prosím vaše internetové připojení.`);
                this.routerExtensions.back();
            });
    }

    onMassAction(event) {
        this.massAction = event.value;
    }

    onToggle(i: number) {
        if (i < 0 || i >= this.selected.length) {
            return;
        }
        this.selected[i] = !this.selected[i];
    }

    onMessage() {
        const selectedPersons = this.getSelectedPersons();
        let isSelectedEmpty = true;
        for (const i in selectedPersons) {
            isSelectedEmpty = false;
        }
        if (isSelectedEmpty) {
            this.showModalNoSelectedPersons();

            return;
        }

        this.store.dispatch(new LoadPhoneNumbers())
        .pipe(withLatestFrom(this.phoneNumbers$))
        .subscribe(([_, output]) => {
            const numbers = [];
            const missingNumbersPersons = [];
            for (const id in selectedPersons) {
                if (output[id]) {
                    numbers.push(output[id]);
                } else {
                    missingNumbersPersons.push(selectedPersons[id]);
                }
            }

            if (missingNumbersPersons.length > 0) {
                this.showModalMissingNumbers(missingNumbersPersons).then(() => this.sendMessage(numbers));
            } else {
                this.sendMessage(numbers);
            }
        }, err => {
            console.log(err);
            feedbackMessage(FeedbackType.Error, 'Načítání dat', `Při načítání dat došlo k chybě. Zkontrolujte prosím vaše internetové připojení.`);
        });
    }

    onEmail() {
        const selectedPersons = this.getSelectedPersons();
        let isSelectedEmpty = true;
        for (const i in selectedPersons) {
            isSelectedEmpty = false;
        }
        if (isSelectedEmpty) {
            this.showModalNoSelectedPersons();

            return;
        }

        this.store.dispatch(new LoadEmails())
            .pipe(withLatestFrom(this.emails$))
            .subscribe(([_, output]) => {
                const emails = [];
                const missingEmailsPersons = [];
                for (const id in selectedPersons) {
                    if (output[id]) {
                        emails.push(output[id]);
                    } else {
                        missingEmailsPersons.push(selectedPersons[id]);
                    }
                }

                if (missingEmailsPersons.length > 0) {
                    this.showModalMissingEmails(missingEmailsPersons).then(() => this.sendEmail(emails));
                } else {
                    this.sendEmail(emails);
                }
            }, err => {
                console.log(err);
                feedbackMessage(FeedbackType.Error, 'Načítání dat', `Při načítání dat došlo k chybě. Zkontrolujte prosím vaše internetové připojení.`);
            });
    }

    onDownload() {
        this.store.dispatch(new LoadExportPerson(this.templateId))
            .pipe(withLatestFrom(this.exportPerson$))
            .subscribe(([_, output]) => {
                this.saveToFolder(output[0]);
            }, err => {
                console.log(err);
                feedbackMessage(FeedbackType.Error, 'Načítání dat', `Při načítání dat došlo k chybě. Zkontrolujte prosím vaše internetové připojení.`);
            });
    }

    changeAllSelected(value: boolean) {
        this.allSelected = !this.allSelected;
        for (let i = 0; i < this.selected.length; i++) {
            this.selected[i] = value;
        }
    }

    onBackButton(): void {
        this.routerExtensions.back();
    }

    private getSelectedPersons(): Object {
        const selected = {};
        this.exportTableData$.subscribe(data => this.selected.forEach((value, index) => {
            if (value) {
                selected[data.ids[index]] = data.persons[index];
            }
        }));

        return selected;
    }

    private sendMessage(numbers: string[]) {
        if (numbers.length) {
            TNSPhone.sms(numbers, '').then(result => {
                    console.dir(result);
                }, error => {
                    console.dir(error);
                });
        }
    }

    private sendEmail(emails: string[]) {
        if (emails.length) {
            TNSEmail.available().then((available: boolean) => {
                if (available) {
                    TNSEmail.compose({
                        to: emails
                    }).then((result) => {
                        console.dir(result);
                    }, (err) => {
                        console.dir(err);
                    });
                }
            });
        }
    }

    private saveToFolder(data: ExportPersonResult) {
        Permissions.requestPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, 'Needed for saving of the file').then(() => {
            let folder;
            if (isAndroid) {
                console.log('We\'re Android.');
                const downloadsFolderPath = android.os.Environment.getExternalStoragePublicDirectory(
                    android.os.Environment.DIRECTORY_DOWNLOADS
                ).toString();
                folder = Folder.fromPath(downloadsFolderPath);
            } else {
                console.log('We\'re iOS.');
                folder = knownFolders.ios.downloads;
            }
            const file = folder.getFile(data.FileName);
            const binaryString = base64.decode(data.Content);
            file.writeTextSync(binaryString, err => {
                console.log('Error saving file');
                console.log(err);
                feedbackMessage(FeedbackType.Error, 'Ukládání souboru', 'Při ukládání souboru došlo k chybě');
            }, encoding.ISO_8859_1);
            feedbackMessage(FeedbackType.Success, 'Stažení souboru',
                `Soubor byl stažen, najdete ho v stažených souborech telefonu pod názvem ${data.FileName}`);
        });
    }

    private showModalMissingNumbers(persons: string[]) {
        const options: ModalDialogOptions = {
            viewContainerRef: this.viewContainerRef,
            context: {
                label: 'Chybějící telefonní čísla',
                message: 'Následujícím osobám nelze odeslat zprávu z důvodu chybějících telefonních čísel v databázi:',
                content: persons
            },
            fullscreen: false
        };

        return this.modalService.showModal(ModalWarningComponent, options);
    }

    private showModalMissingEmails(persons: string[]) {
        const options: ModalDialogOptions = {
            viewContainerRef: this.viewContainerRef,
            context: {
                label: 'Chybějící e-maily',
                message: 'Následujícím osobám nelze odeslat e-mail z důvodu chybějících e-mailů v databázi:',
                content: persons
            },
            fullscreen: false
        };

        return this.modalService.showModal(ModalWarningComponent, options);
    }

    private showModalNoSelectedPersons() {
        const options: ModalDialogOptions = {
            viewContainerRef: this.viewContainerRef,
            context: {
                label: 'Žádní příjemci',
                message: 'Nebyli zvoleni žádní příjemci.',
                height: '10%'
            },
            fullscreen: false
        };

        return this.modalService.showModal(ModalWarningComponent, options);
    }

    get smsIcon() {
        return String.fromCharCode(0xf086);
    }

    get emailIcon() {
        return String.fromCharCode(0xf0e0);
    }

    get downloadIcon() {
        return String.fromCharCode(0xf56d);
    }
}
