import { Injectable } from '@angular/core';
import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { delay, mergeMap, materialize, dematerialize } from 'rxjs/operators';
import {FireForm} from "@/_models/fire-form";

// array in local storage for registered users
let users = JSON.parse(localStorage.getItem('users')) || [];
let forms = JSON.parse(localStorage.getItem('forms')) || [];
let companies = JSON.parse(localStorage.getItem('companies')) || [];

@Injectable()
export class FakeBackendInterceptor implements HttpInterceptor {
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        const { url, method, headers, body } = request;

        // wrap in delayed observable to simulate server api call
        return of(null)
            .pipe(mergeMap(handleRoute))
            .pipe(materialize()) // call materialize and dematerialize to ensure delay even if an error is thrown (https://github.com/Reactive-Extensions/RxJS/issues/648)
            .pipe(delay(500))
            .pipe(dematerialize());

        function handleRoute() {
            switch (true) {
                case url.endsWith('/users/authenticate') && method === 'POST':
                    return authenticate();
                case url.endsWith('/users/register') && method === 'POST':
                    return register();
                case url.endsWith('/companies/register') && method === 'POST':
                    return registerCompany();
                case url.endsWith('/fireAndSecurity') && method === 'GET':
                    return getForms();
                case url.endsWith('/companies') && method === 'GET':
                    return getCompanies();
                case url.endsWith('/hotWorkPermits') && method === 'GET':
                    return getHWPForms();
                case url.endsWith('/forms/fireAndSecurity') && method === 'POST':
                    return addForms();
                case url.endsWith('/users') && method === 'GET':
                    return getUsers();
                case url.match(/\/users\/\d+$/) && method === 'DELETE':
                    return deleteUser();
                case url.match(/\/companies\/\d+$/) && method === 'DELETE':
                    return deleteCompany();
                default:
                    // pass through any requests not handled above
                    return next.handle(request);
            }    
        }

        // route functions

        function authenticate() {
            const { username, password } = body;
            const user = users.find(x => x.username === username && x.password === password);
            if (!user) return error('Username or password is incorrect');
            return ok({
                id: user.id,
                username: user.username,
                first_name: user.first_name,
                last_name: user.last_name,
                token: 'fake-jwt-token',
                is_admin: user.is_admin,
                approved: user.approved
            })
        }

        function register() {
            const user = body
            if (users.find(x => x.username === user.username)) {
                return error('Username "' + user.username + '" is already taken')
            }
            user.id = users.length ? Math.max(...users.map(x => x.id)) + 1 : 1;
            users.push(user);
            localStorage.setItem('users', JSON.stringify(users));
            return ok();
        }

        function registerCompany() {
            const company = body
            if (company.id == null) {
                company.id = companies.length ? Math.max(...users.map(x => x.id)) + 1 : 1;
                if (companies.find(x => x.name === company.name)) {
                    return error('company with name "' + company.name + '" is already taken')
                }
                companies.push(company);
            } else { // update
                companies[company.id] = company;
            }
            localStorage.setItem('companies', JSON.stringify(companies));
            return ok();
        }

        function addForms() {
            const fireForm = body
            forms.id = forms.length ? Math.max(...forms.map(x => x.id)) + 1 : 1;
            forms.push(fireForm);
            localStorage.setItem('forms', JSON.stringify(forms));
            return ok();
        }

        function getUsers() {
            if (!isLoggedIn()) return unauthorized();
            return ok(users);
        }

        function getCompanies() {
            if (!isLoggedIn()) return unauthorized();
            return ok(companies);
        }

        function getForms() {
            if (!isLoggedIn()) return unauthorized();
            return ok(forms);
        }

        function getHWPForms() {
            if (!isLoggedIn()) return unauthorized();
            let temForm: FireForm [] = new Array();
            for (var i = 0; i < forms.length; i++) {
                if (forms[i].hotWorkPermit) {
                    temForm.push(forms[i]);
                }
            }
            return ok(temForm);
        }

        function deleteUser() {
            if (!isLoggedIn()) return unauthorized();
            users = users.filter(x => x.id !== idFromUrl());
            localStorage.setItem('users', JSON.stringify(users));
            return ok();
        }

        function deleteCompany() {
            if (!isLoggedIn()) return unauthorized();
            companies = companies.filter(x => x.id !== idFromUrl());
            localStorage.setItem('companies', JSON.stringify(companies));
            return ok();
        }
        // helper functions

        function ok(body?) {
            return of(new HttpResponse({ status: 200, body }))
        }

        function error(message) {
            return throwError({ error: { message } });
        }

        function unauthorized() {
            return throwError({ status: 401, error: { message: 'Unauthorised' } });
        }

        function isLoggedIn() {
            return headers.get('Authorization') === 'Bearer fake-jwt-token';
        }

        function idFromUrl() {
            const urlParts = url.split('/');
            return parseInt(urlParts[urlParts.length - 1]);
        }
    }
}

export const fakeBackendProvider = {
    // use fake backend in place of Http service for backend-less development
    provide: HTTP_INTERCEPTORS,
    useClass: FakeBackendInterceptor,
    multi: true
};