import { Injectable, inject } from '@angular/core';
import { HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

import { ApiService } from '../api.service';
import {
    HWActivityStat,
    HWClan,
    HWClanList,
    HWClanListConfig,
    HWClanListFilters,
    HWClanPageData,
    HWGuildClan,
    HWMember,
} from '@models';
import { HWDataService } from './hw-data.service';

@Injectable({ providedIn: 'root' })
export class HWClanService {
    private apiService = inject(ApiService);
    private _dataService = inject(HWDataService);

    private _apiDomain = '/herowars';

    private _resetActivity(): HWActivityStat {
        const activity: HWActivityStat = {
            activity: 0,
            prestige: 0,
            titanite: 0,
            war: 0,
            adventure: 0,
            gifts: 0,
            score: 0,
            scoreGifts: 0,
            warGifts: 0,
            rewards: 0,
        };
        return activity;
    }

    query(config: HWClanListConfig): Observable<HWClanList> {
        // Convert any filters over to Angular's URLSearchParams
        const params: HWClanListFilters = {} as HWClanListFilters;
        Object.assign(params, config.filters);
        return this.apiService.get(
            `${this._apiDomain}/clans`,
            new HttpParams({ fromObject: <
                    {
                        [param: string]: string | number | boolean | readonly (string | number | boolean)[];
                    }
                >params }),
        );
    }

    get(id: string): Observable<HWClanPageData> {
        return this.apiService.get(`${this._apiDomain}/clans/${id}`);
    }

    getAll(): Observable<Array<HWClan>> {
        return this.apiService.get(`${this._apiDomain}/clans`).pipe(map((data) => data.clans));
    }

    create(clan: HWClan): Observable<HWClan> {
        return this.apiService.post(`${this._apiDomain}/clans/`, { clan: clan }).pipe(map((data) => data.clan));
    }

    update(clan: HWClan): Observable<HWClan> {
        return this.apiService
            .put(`${this._apiDomain}/clans/${clan.id}`, { clan: clan })
            .pipe(map((data) => data.clan));
    }

    destroy(id: string): Observable<boolean> {
        return this.apiService.delete(`${this._apiDomain}/clans/${id}`).pipe(map((data) => data.deleted));
    }

    save(clan: HWClan): Observable<HWClan> {
        // If we're updating an existing clan
        if (clan.id) {
            return this.apiService
                .put(`${this._apiDomain}/clans/${clan.id}`, { clan: clan })
                .pipe(map((data) => data.clan));
            // Otherwise, create a new clan
        } else {
            return this.apiService.post(`${this._apiDomain}/clans/`, { clan: clan }).pipe(map((data) => data.clan));
        }
    }

    loadClan(): Observable<HWGuildClan> {
        return this._dataService.guildData$.pipe(
            map((guildData) => {
                const guildClan: HWGuildClan = {} as HWGuildClan;
                Object.assign(guildClan, guildData.clan);
                guildClan.sumAverages = this._resetActivity();
                guildClan.sumTotal = this._resetActivity();
                guildClan.todayAverages = this._resetActivity();
                guildClan.todayTotal = this._resetActivity();
                return guildClan;
            }),
        );
    }

    loadClanStats(clan: HWGuildClan, members: HWMember[]): HWGuildClan {
        members.map((member: HWMember) => {
            clan.sumTotal.adventure += member.adventureSum;
            clan.sumTotal.gifts += member.clanGiftsSum;
            clan.sumTotal.war += member.clanWarSum;
            clan.todayTotal.activity += member.stat.todayActivity;
            clan.todayTotal.prestige += member.stat.todayPrestige;
            clan.todayTotal.titanite += member.stat.todayDungeonActivity;
            clan.todayTotal.score +=
                member.stat.todayDungeonActivity + member.stat.todayActivity + member.stat.todayPrestige;
            clan.sumTotal.activity += member.stat.activitySum;
            clan.sumTotal.prestige += member.stat.prestigeSum;
            clan.sumTotal.titanite += member.stat.dungeonActivitySum;
            clan.sumTotal.score += member.score;
            clan.sumTotal.warGifts += member.warGifts;
        });
        clan.sumTotal.scoreGifts = clan.giftsCount - Math.floor(clan.sumTotal.warGifts);
        clan.todayAverages.activity = clan.todayTotal.activity / members.length;
        clan.todayAverages.prestige = clan.todayTotal.prestige / members.length;
        clan.todayAverages.titanite = clan.todayTotal.titanite / members.length;
        clan.todayAverages.score = clan.todayTotal.score / members.length;
        clan.sumAverages.activity = clan.sumTotal.activity / members.length;
        clan.sumAverages.prestige = clan.sumTotal.prestige / members.length;
        clan.sumAverages.titanite = clan.sumTotal.titanite / members.length;
        if (clan.league === '3') {
            clan.sumAverages.war = clan.sumTotal.war / 10;
        } else if (clan.league === '2') {
            clan.sumAverages.war = clan.sumTotal.war / 15;
        } else if (clan.league === '1') {
            clan.sumAverages.war = clan.sumTotal.war / 20;
        }
        clan.sumAverages.adventure = clan.sumTotal.adventure / members.length;
        clan.sumAverages.gifts = clan.sumTotal.gifts / members.length;
        clan.sumAverages.score = clan.sumTotal.score / members.length;
        clan.sumAverages.scoreGifts = clan.sumTotal.scoreGifts / members.length;
        clan.sumAverages.warGifts = clan.sumTotal.warGifts / members.length;
        members.map((data) => {
            data.scoreGifts = (data.score / clan.sumTotal.score) * clan.sumTotal.scoreGifts;
            data.rewards = Math.floor(data.scoreGifts + data.warGifts);
            clan.sumTotal.rewards += data.rewards;
            return data;
        });
        clan.sumAverages.rewards = clan.sumTotal.rewards / members.length;

        return clan;
    }
}
