<template>
    <v-container fluid fill-height class="no-padding">
        <v-layout row wrap fill-height>
            <v-flex xs12 fill-height v-if="lat && lng">
                <Map :lat="lat" :lng="lng" :heading="heading" :markers="reportsMarkers"></Map>
                <v-btn
                    fixed
                    dark
                    fab
                    bottom
                    right
                    color="orange"
                    class="overlayButton"
                    @click.native.stop="dialog = !dialog"
                    >
                    <v-icon>report_problem</v-icon>
                </v-btn>
                <ReportDialog v-model="dialog" :lat="lat" :lng="lng"></ReportDialog>
            </v-flex>
            <v-flex xs12 fill-height v-else class="pa-3">
                <p>{{ error }}</p>
                <p class="text-xs-center">
                    <v-btn color="blue" dark @click="initializePositionWatching">Retry</v-btn>
                </p>
            </v-flex>
        </v-layout>
    </v-container>
</template>

<script>
import NoSleep from 'nosleep.js';

import * as api from '@/api';
import Map from '@/components/Map.vue';
import ReportDialog from '@/components/ReportDialog/index.vue';
import { distance, mockLocation } from '@/tools';

const MOCK_LOCATION = false;
const MOCK_LOCATION_UPDATE_INTERVAL = 30 * 1000;
const UPDATE_REPORTS_DISTANCE_THRESHOLD = 500;

export default {
    components: {
        Map,
        ReportDialog,
    },
    created() {
        this.initializePositionWatching();
        this.setNoSleep();
        this.fetchReports();
    },
    beforeDestroy() {
        this.disableNoSleep();
        this.disablePositionWatching();
    },
    computed: {
        reportsMarkers() {
            if (!this.reports) {
                return [];
            }
            return this.reports.map(report => ({
                id: report.id,
                latLng: [report.attributes.lat, report.attributes.lng],
            }));
        },
    },
    data() {
        return {
            dialog: false,
            error: this.$t('geolocation.enable'),
            heading: null,
            lat: null,
            lng: null,
            noSleep: null,
            reports: null,
            watchID: null,
        };
    },
    methods: {
        initializePositionWatching() {
            this.disablePositionWatching(); // Ensure at most one at the same time

            if (MOCK_LOCATION) {
                this.setPosition(mockLocation());
                this.watchID = setInterval(
                    () => this.setPosition(mockLocation()),
                    MOCK_LOCATION_UPDATE_INTERVAL,
                );
            } else {
                if (!('geolocation' in navigator)) {
                    this.error = this.$t('geolocation.unavailable');
                }

                this.watchID = navigator.geolocation.watchPosition(
                    this.setPosition,
                    this.handlePositionError,
                    {
                        enableHighAccuracy: true,
                        maximumAge: 30000,
                        timeout: 27000,
                    },
                );
            }
        },
        disablePositionWatching() {
            if (this.watchID !== null) {
                if (MOCK_LOCATION) {
                    clearInterval(this.watchID);
                } else {
                    navigator.geolocation.clearWatch(this.watchID);
                }
            }
        },
        handlePositionError(error) {
            this.error = `Error ${error.code}: ${error.message}`;
        },
        setPosition(position) {
            if (this.lat && this.lng) {
                const distanceFromPreviousPoint = distance(
                    [this.lat, this.lng],
                    [position.coords.latitude, position.coords.longitude],
                );
                if (distanceFromPreviousPoint > UPDATE_REPORTS_DISTANCE_THRESHOLD) {
                    this.fetchReports();
                }
            }
            this.lat = position.coords.latitude;
            this.lng = position.coords.longitude;
            if (position.coords.heading) {
                this.heading = position.coords.heading;
            } else {
                this.heading = null;
            }
        },
        setNoSleep() {
            this.noSleep = new NoSleep();
            this.noSleep.enable();
        },
        disableNoSleep() {
            if (this.noSleep) {
                this.noSleep.disable();
            }
        },
        fetchReports() {
            api.getReports().then((reports) => {
                this.reports = reports;
            });
        },
    },
};
</script>

<style scoped>
.no-padding {
    padding: 0;
}

.overlayButton {
    z-index: 1000 !important;
}
</style>

<style>
.overlay {
    z-index: 1002 !important;
}
</style>
