// Core imports
import {
  HTTP_INTERCEPTORS,
  HttpEvent,
  HttpHandler,
  HttpInterceptor,
  HttpRequest,
  HttpResponse,
} from '@angular/common/http';
import { Injectable } from '@angular/core';

// Third party imports
import { Observable, of, throwError } from 'rxjs';
import { delay, dematerialize, materialize, mergeMap } from 'rxjs/operators';

// Application imports
import { Action } from '@app/_models';

/** A mock of the curated account types. */
const accountTypes: Array<string> = ['user', 'cashier', 'vendor', 'tokenagent', 'group'];

/** A mock of actions made by the admin staff. */
const actions: Array<Action> = [
  { id: 1, user: 'Tom', role: 'enroller', action: 'Disburse RSV 100', approval: false },
  { id: 2, user: 'Christine', role: 'admin', action: 'Change user phone number', approval: true },
  { id: 3, user: 'Will', role: 'superadmin', action: 'Reclaim RSV 1000', approval: true },
  { id: 4, user: 'Vivian', role: 'enroller', action: 'Complete user profile', approval: true },
  { id: 5, user: 'Jack', role: 'enroller', action: 'Reclaim RSV 200', approval: false },
  { id: 6, user: 'Patience', role: 'enroller', action: 'Change user information', approval: false },
];

/** A mock of curated area names. */
const areaNames: object = {
  'Mukuru Nairobi': [
    'kayaba',
    'kayba',
    'kambi',
    'mukuru',
    'masai',
    'hazina',
    'south',
    'tetra',
    'tetrapak',
    'ruben',
    'rueben',
    'kingston',
    'korokocho',
    'kingstone',
    'kamongo',
    'lungalunga',
    'sinai',
    'sigei',
    'lungu',
    'lunga lunga',
    'owino road',
    'seigei',
  ],
  'Kinango Kwale': [
    'amani',
    'bofu',
    'chibuga',
    'chikomani',
    'chilongoni',
    'chigojoni',
    'chinguluni',
    'chigato',
    'chigale',
    'chikole',
    'chilongoni',
    'chilumani',
    'chigojoni',
    'chikomani',
    'chizini',
    'chikomeni',
    'chidzuvini',
    'chidzivuni',
    'chikuyu',
    'chizingo',
    'doti',
    'dzugwe',
    'dzivani',
    'dzovuni',
    'hanje',
    'kasemeni',
    'katundani',
    'kibandaogo',
    'kibandaongo',
    'kwale',
    'kinango',
    'kidzuvini',
    'kalalani',
    'kafuduni',
    'kaloleni',
    'kilibole',
    'lutsangani',
    'peku',
    'gona',
    'guro',
    'gandini',
    'mkanyeni',
    'myenzeni',
    'miyenzeni',
    'miatsiani',
    'mienzeni',
    'mnyenzeni',
    'minyenzeni',
    'miyani',
    'mioleni',
    'makuluni',
    'mariakani',
    'makobeni',
    'madewani',
    'mwangaraba',
    'mwashanga',
    'miloeni',
    'mabesheni',
    'mazeras',
    'mazera',
    'mlola',
    'muugano',
    'mulunguni',
    'mabesheni',
    'miatsani',
    'miatsiani',
    'mwache',
    'mwangani',
    'mwehavikonje',
    'miguneni',
    'nzora',
    'nzovuni',
    'vikinduni',
    'vikolani',
    'vitangani',
    'viogato',
    'vyogato',
    'vistangani',
    'yapha',
    'yava',
    'yowani',
    'ziwani',
    'majengo',
    'matuga',
    'vigungani',
    'vidziweni',
    'vinyunduni',
    'ukunda',
    'kokotoni',
    'mikindani',
  ],
  'Misc Nairobi': [
    'nairobi',
    'west',
    'lindi',
    'kibera',
    'kibira',
    'kibra',
    'makina',
    'soweto',
    'olympic',
    'kangemi',
    'ruiru',
    'congo',
    'kawangware',
    'kwangware',
    'donholm',
    'dagoreti',
    'dandora',
    'kabete',
    'sinai',
    'donhom',
    'donholm',
    'huruma',
    'kitengela',
    'makadara',
    ',mlolongo',
    'kenyatta',
    'mlolongo',
    'tassia',
    'tasia',
    'gatina',
    '56',
    'industrial',
    'kariobangi',
    'kasarani',
    'kayole',
    'mathare',
    'pipe',
    'juja',
    'uchumi',
    'jogoo',
    'umoja',
    'thika',
    'kikuyu',
    'stadium',
    'buru buru',
    'ngong',
    'starehe',
    'mwiki',
    'fuata',
    'kware',
    'kabiro',
    'embakassi',
    'embakasi',
    'kmoja',
    'east',
    'githurai',
    'landi',
    'langata',
    'limuru',
    'mathere',
    'dagoretti',
    'kirembe',
    'muugano',
    'mwiki',
    'toi market',
  ],
  'Kisauni Mombasa': [
    'bamburi',
    'mnyuchi',
    'kisauni',
    'kasauni',
    'mworoni',
    'nyali',
    'falcon',
    'shanzu',
    'bombolulu',
    'kandongo',
    'kadongo',
    'mshomoro',
    'mtopanga',
    'mjambere',
    'majaoni',
    'manyani',
    'magogoni',
    'magongoni',
    'junda',
    'mwakirunge',
    'mshomoroni',
    'mjinga',
    'mlaleo',
    'utange',
  ],
  'Misc Mombasa': [
    'mombasa',
    'likoni',
    'bangla',
    'bangladesh',
    'kizingo',
    'old town',
    'makupa',
    'mvita',
    'ngombeni',
    'ngómbeni',
    'ombeni',
    'magongo',
    'miritini',
    'changamwe',
    'jomvu',
    'ohuru',
    'tudor',
    'diani',
  ],
  Kilifi: [
    'kilfi',
    'kilifi',
    'mtwapa',
    'takaungu',
    'makongeni',
    'mnarani',
    'mnarani',
    'office',
    'g.e',
    'ge',
    'raibai',
    'ribe',
  ],
  Kakuma: ['kakuma'],
  Kitui: ['kitui', 'mwingi'],
  Nyanza: [
    'busia',
    'nyalgunga',
    'mbita',
    'siaya',
    'kisumu',
    'nyalenda',
    'hawinga',
    'rangala',
    'uyoma',
    'mumias',
    'homabay',
    'homaboy',
    'migori',
    'kusumu',
  ],
  'Misc Rural Counties': [
    'makueni',
    'meru',
    'kisii',
    'bomet',
    'machakos',
    'bungoma',
    'eldoret',
    'kakamega',
    'kericho',
    'kajiado',
    'nandi',
    'nyeri',
    'wote',
    'kiambu',
    'mwea',
    'nakuru',
    'narok',
  ],
  other: ['other', 'none', 'unknown'],
};

const areaTypes: object = {
  urban: ['urban', 'nairobi', 'mombasa', 'kisauni'],
  rural: ['rural', 'kakuma', 'kwale', 'kinango', 'kitui', 'nyanza'],
  periurban: ['kilifi', 'periurban'],
  other: ['other'],
};

/** A mock of the user's business categories */
const categories: object = {
  system: ['system', 'office main', 'office main phone'],
  education: [
    'book',
    'coach',
    'teacher',
    'sch',
    'school',
    'pry',
    'education',
    'student',
    'mwalimu',
    'maalim',
    'consultant',
    'consult',
    'college',
    'university',
    'lecturer',
    'primary',
    'secondary',
    'daycare',
    'babycare',
    'baby care',
    'elim',
    'eimu',
    'nursery',
    'red cross',
    'volunteer',
    'instructor',
    'journalist',
    'lesson',
    'academy',
    'headmistress',
    'headteacher',
    'cyber',
    'researcher',
    'professor',
    'demo',
    'expert',
    'tution',
    'children',
    'headmaster',
    'educator',
    'Marital counsellor',
    'counsellor',
    'trainer',
    'vijana',
    'youth',
    'intern',
    'redcross',
    'KRCS',
    'danish',
    'science',
    'data',
    'facilitator',
    'vitabu',
    'kitabu',
  ],
  faith: [
    'pastor',
    'imam',
    'madrasa',
    'religous',
    'religious',
    'ustadh',
    'ustadhi',
    'Marital counsellor',
    'counsellor',
    'church',
    'kanisa',
    'mksiti',
    'donor',
  ],
  government: [
    'elder',
    'chief',
    'police',
    'government',
    'country',
    'county',
    'soldier',
    'village admin',
    'ward',
    'leader',
    'kra',
    'mailman',
    'immagration',
  ],
  environment: [
    'conservation',
    'toilet',
    'choo',
    'garbage',
    'fagio',
    'waste',
    'tree',
    'taka',
    'scrap',
    'cleaning',
    'gardener',
    'rubbish',
    'usafi',
    'mazingira',
    'miti',
    'trash',
    'cleaner',
    'plastic',
    'collection',
    'seedling',
    'seedlings',
    'recycling',
  ],
  farming: [
    'farm',
    'farmer',
    'farming',
    'mkulima',
    'kulima',
    'ukulima',
    'wakulima',
    'jembe',
    'shamba',
  ],
  labour: [
    'artist',
    'agent',
    'guard',
    'askari',
    'accountant',
    'baker',
    'beadwork',
    'beauty',
    'business',
    'barber',
    'casual',
    'electrian',
    'caretaker',
    'car wash',
    'capenter',
    'construction',
    'chef',
    'catering',
    'cobler',
    'cobbler',
    'carwash',
    'dhobi',
    'landlord',
    'design',
    'carpenter',
    'fundi',
    'hawking',
    'hawker',
    'househelp',
    'hsehelp',
    'house help',
    'help',
    'housegirl',
    'kushona',
    'juakali',
    'jualikali',
    'juacali',
    'jua kali',
    'shepherd',
    'makuti',
    'kujenga',
    'kinyozi',
    'kazi',
    'knitting',
    'kufua',
    'fua',
    'hustler',
    'biashara',
    'labour',
    'labor',
    'laundry',
    'repair',
    'hair',
    'posho',
    'mill',
    'mtambo',
    'uvuvi',
    'engineer',
    'manager',
    'tailor',
    'nguo',
    'mason',
    'mtumba',
    'garage',
    'mechanic',
    'mjenzi',
    'mfugaji',
    'painter',
    'receptionist',
    'printing',
    'programming',
    'plumb',
    'charging',
    'salon',
    'mpishi',
    'msusi',
    'mgema',
    'footballer',
    'photocopy',
    'peddler',
    'staff',
    'sales',
    'service',
    'saloon',
    'seremala',
    'security',
    'insurance',
    'secretary',
    'shoe',
    'shepard',
    'shephard',
    'tout',
    'tv',
    'mvuvi',
    'mawe',
    'majani',
    'maembe',
    'freelance',
    'mjengo',
    'electronics',
    'photographer',
    'programmer',
    'electrician',
    'washing',
    'bricks',
    'welder',
    'welding',
    'working',
    'worker',
    'watchman',
    'waiter',
    'waitress',
    'viatu',
    'yoga',
    'guitarist',
    'house',
    'artisan',
    'musician',
    'trade',
    'makonge',
    'ujenzi',
    'vendor',
    'watchlady',
    'marketing',
    'beautician',
    'photo',
    'metal work',
    'supplier',
    'law firm',
    'brewer',
  ],
  food: [
    'avocado',
    'bhajia',
    'bajia',
    'mbonga',
    'bofu',
    'beans',
    'biscuits',
    'biringanya',
    'banana',
    'bananas',
    'crisps',
    'chakula',
    'coconut',
    'chapati',
    'cereal',
    'chipo',
    'chapo',
    'chai',
    'chips',
    'cassava',
    'cake',
    'cereals',
    'cook',
    'corn',
    'coffee',
    'chicken',
    'dagaa',
    'donut',
    'dough',
    'groundnuts',
    'hotel',
    'holel',
    'hoteli',
    'butcher',
    'butchery',
    'fruit',
    'food',
    'fruits',
    'fish',
    'githeri',
    'grocery',
    'grocer',
    'pojo',
    'papa',
    'goats',
    'mabenda',
    'mbenda',
    'poultry',
    'soda',
    'peanuts',
    'potatoes',
    'samosa',
    'soko',
    'samaki',
    'tomato',
    'tomatoes',
    'mchele',
    'matunda',
    'mango',
    'melon',
    'mellon',
    'nyanya',
    'nyama',
    'omena',
    'umena',
    'ndizi',
    'njugu',
    'kamba kamba',
    'khaimati',
    'kaimati',
    'kunde',
    'kuku',
    'kahawa',
    'keki',
    'muguka',
    'miraa',
    'milk',
    'choma',
    'maziwa',
    'mboga',
    'mbog',
    'busaa',
    'chumvi',
    'cabbages',
    'mabuyu',
    'machungwa',
    'mbuzi',
    'mnazi',
    'mchicha',
    'ngombe',
    'ngano',
    'nazi',
    'oranges',
    'peanuts',
    'mkate',
    'bread',
    'mikate',
    'vitungu',
    'sausages',
    'maize',
    'mbata',
    'mchuzi',
    'mchuuzi',
    'mandazi',
    'mbaazi',
    'mahindi',
    'maandazi',
    'mogoka',
    'meat',
    'mhogo',
    'mihogo',
    'muhogo',
    'maharagwe',
    'miwa',
    'mahamri',
    'mitumba',
    'simsim',
    'porridge',
    'pilau',
    'vegetable',
    'egg',
    'mayai',
    'mifugo',
    'unga',
    'good',
    'sima',
    'sweet',
    'sweats',
    'sambusa',
    'snacks',
    'sugar',
    'suger',
    'ugoro',
    'sukari',
    'soup',
    'spinach',
    'smokie',
    'smokies',
    'sukuma',
    'tea',
    'uji',
    'ugali',
    'uchuzi',
    'uchuuzi',
    'viazi',
    'yoghurt',
    'yogurt',
    'wine',
    'marondo',
    'maandzi',
    'matoke',
    'omeno',
    'onions',
    'nzugu',
    'korosho',
    'barafu',
    'juice',
  ],
  water: ['maji', 'water'],
  health: [
    'agrovet',
    'dispensary',
    'barakoa',
    'chemist',
    'Chemicals',
    'chv',
    'doctor',
    'daktari',
    'dawa',
    'hospital',
    'herbalist',
    'mganga',
    'sabuni',
    'soap',
    'nurse',
    'heath',
    'community health worker',
    'clinic',
    'clinical',
    'mask',
    'medicine',
    'lab technician',
    'pharmacy',
    'cosmetics',
    'veterinary',
    'vet',
    'sickly',
    'emergency response',
    'emergency',
  ],
  savings: ['chama', 'group', 'savings', 'loan', 'silc', 'vsla', 'credit', 'finance'],
  shop: [
    'bag',
    'bead',
    'belt',
    'bedding',
    'jik',
    'bed',
    'cement',
    'botique',
    'boutique',
    'lines',
    'kibanda',
    'kiosk',
    'spareparts',
    'candy',
    'cloth',
    'electricals',
    'mutumba',
    'cafe',
    'leso',
    'lesso',
    'duka',
    'spare parts',
    'socks',
    'malimali',
    'mitungi',
    'mali mali',
    'hardware',
    'detergent',
    'detergents',
    'dera',
    'retail',
    'kamba',
    'pombe',
    'pampers',
    'pool',
    'phone',
    'simu',
    'mangwe',
    'mikeka',
    'movie',
    'shop',
    'acces',
    'mchanga',
    'uto',
    'airtime',
    'matress',
    'mattress',
    'mattresses',
    'mpsea',
    'mpesa',
    'shirt',
    'wholesaler',
    'perfume',
    'playstation',
    'tissue',
    'vikapu',
    'uniform',
    'flowers',
    'vitenge',
    'utencils',
    'utensils',
    'station',
    'jewel',
    'pool table',
    'club',
    'pub',
    'bar',
    'furniture',
    'm-pesa',
    'vyombo',
  ],
  transport: [
    'kebeba',
    'beba',
    'bebabeba',
    'bike',
    'bicycle',
    'matatu',
    'boda',
    'bodaboda',
    'cart',
    'carrier',
    'tour',
    'travel',
    'driver',
    'dereva',
    'tout',
    'conductor',
    'kubeba',
    'tuktuk',
    'taxi',
    'piki',
    'pikipiki',
    'manamba',
    'trasportion',
    'mkokoteni',
    'mover',
    'motorist',
    'motorbike',
    'transport',
    'transpoter',
    'gari',
    'magari',
    'makanga',
    'car',
  ],
  'fuel/energy': [
    'timber',
    'timberyard',
    'biogas',
    'charcol',
    'charcoal',
    'kuni',
    'mbao',
    'fuel',
    'makaa',
    'mafuta',
    'moto',
    'solar',
    'stima',
    'fire',
    'firewood',
    'wood',
    'oil',
    'taa',
    'gas',
    'paraffin',
    'parrafin',
    'parafin',
    'petrol',
    'petro',
    'kerosine',
    'kerosene',
    'diesel',
  ],
  other: ['other', 'none', 'unknown', 'none'],
};

/** A mock of curated genders */
const genders: Array<string> = ['male', 'female', 'other'];

/** A mock of curated  transaction types. */
const transactionTypes: Array<string> = [
  'transactions',
  'conversions',
  'disbursements',
  'rewards',
  'reclamations',
];

/**
 * Intercepts HTTP requests and handles some specified requests internally.
 * Provides a backend that can handle requests for certain data items.
 */
@Injectable()
export class MockBackendInterceptor implements HttpInterceptor {
  /**
   * Intercepts HTTP requests.
   *
   * @param request - An outgoing HTTP request with an optional typed body.
   * @param next - The next HTTP handler or the outgoing request dispatcher.
   * @returns The response from the resolved request.
   */
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const { url, method, headers, body } = request;

    // wrap in delayed observable to simulate server api call\
    // call materialize and dematerialize to ensure delay even is thrown
    return of(null)
      .pipe(mergeMap(handleRoute))
      .pipe(materialize())
      .pipe(delay(500))
      .pipe(dematerialize());

    /** Forward requests from select routes to their internal handlers. */
    function handleRoute(): Observable<any> {
      switch (true) {
        case url.endsWith('/accounttypes') && method === 'GET':
          return getAccountTypes();
        case url.endsWith('/actions') && method === 'GET':
          return getActions();
        case url.match(/\/actions\/\d+$/) && method === 'GET':
          return getActionById();
        case url.match(/\/actions\/\d+$/) && method === 'POST':
          return approveAction();
        case url.endsWith('/areanames') && method === 'GET':
          return getAreaNames();
        case url.endsWith('/areatypes') && method === 'GET':
          return getAreaTypes();
        case url.endsWith('/categories') && method === 'GET':
          return getCategories();
        case url.endsWith('/genders') && method === 'GET':
          return getGenders();
        case url.endsWith('/transactiontypes') && method === 'GET':
          return getTransactionTypes();
        default:
          // pass through any requests not handled above
          return next.handle(request);
      }
    }

    // route functions

    function approveAction(): Observable<HttpResponse<any>> {
      const queriedAction: Action = actions.find((action) => action.id === idFromUrl());
      queriedAction.approval = body.approval;
      const message: string = `Action approval status set to ${body.approval} successfully!`;
      return ok(message);
    }

    function getAccountTypes(): Observable<HttpResponse<any>> {
      return ok(accountTypes);
    }

    function getActions(): Observable<HttpResponse<any>> {
      return ok(actions);
    }

    function getActionById(): Observable<HttpResponse<any>> {
      const queriedAction: Action = actions.find((action) => action.id === idFromUrl());
      return ok(queriedAction);
    }

    function getAreaNames(): Observable<HttpResponse<any>> {
      return ok(areaNames);
    }

    function getAreaTypes(): Observable<HttpResponse<any>> {
      return ok(areaTypes);
    }

    function getCategories(): Observable<HttpResponse<any>> {
      return ok(categories);
    }

    function getGenders(): Observable<HttpResponse<any>> {
      return ok(genders);
    }

    function getTransactionTypes(): Observable<HttpResponse<any>> {
      return ok(transactionTypes);
    }

    // helper functions

    function error(message): Observable<any> {
      return throwError({ status: 400, error: { message } });
    }

    function idFromUrl(): number {
      const urlParts: Array<string> = url.split('/');
      return parseInt(urlParts[urlParts.length - 1], 10);
    }

    function ok(responseBody: any): Observable<HttpResponse<any>> {
      return of(new HttpResponse({ status: 200, body: responseBody }));
    }

    function stringFromUrl(): string {
      const urlParts: Array<string> = url.split('/');
      return urlParts[urlParts.length - 1];
    }
  }
}

/** Exports the MockBackendInterceptor as an Angular provider. */
export const MockBackendProvider = {
  provide: HTTP_INTERCEPTORS,
  useClass: MockBackendInterceptor,
  multi: true,
};
