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

import { ApiService, UtilitiesService } from '@services';
import {
    HWGuildClan,
    HWWeekStat,
    HWMember,
    HWMemberList,
    HWMemberListConfig,
    HWMemberListFilters,
    HWMemberPageData,
    HWMemberStat,
} from '@models';
import { HWDataService } from './hw-data.service';
@Injectable({ providedIn: 'root' })
export class HWMemberService {
    private _apiService = inject(ApiService);
    private _utilitiesService = inject(UtilitiesService);
    private _dataService = inject(HWDataService);

    private _apiDomain = '/herowars';

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

    get(id: string): Observable<HWMemberPageData> {
        return this._apiService.get(`${this._apiDomain}/members/${id}`);
    }

    getAll(): Observable<Array<HWMember>> {
        return this._apiService.get(`${this._apiDomain}/members`).pipe(map((data) => data.members));
    }

    create(member: HWMember): Observable<HWMember> {
        return this._apiService
            .post(`${this._apiDomain}/members/`, { member: member })
            .pipe(map((data) => data.member));
    }

    update(member: HWMember): Observable<HWMember> {
        return this._apiService
            .put(`${this._apiDomain}/members/${member.id}`, { member: member })
            .pipe(map((data) => data.member));
    }

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

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

    loadMembers(clan: HWGuildClan): Observable<HWMember[]> {
        return combineLatest([this._dataService.guildData$, this._dataService.guildStatistics$]).pipe(
            map(([guildData, guildStatistics]) => {
                const guildMembers: HWMember[] = [];
                const now = new Date();
                const oneDayInSec = 24 * 60 * 60;
                const daysToKick = parseInt(guildData.clan.daysToKick);
                for (const data of Object.entries(guildData.clan.members)) {
                    const member: HWMember = {} as HWMember;
                    Object.assign(member, data[1]);
                    member.champion = guildData.clan.warriors.indexOf(parseInt(member.id)) !== -1;
                    member.heroes = { power: 0, teams: [] };
                    member.titans = { power: 0, teams: [] };
                    guildMembers.push(member);
                }
                guildMembers.map((data: HWMember) => {
                    const last = new Date(parseInt(data.lastLoginTime) * 1000);
                    const exp = new Date(last.getTime() + daysToKick * oneDayInSec * 1000);
                    const diff = Math.floor((exp.getTime() - now.getTime()) / 1000);
                    const daysLeft = Math.floor(diff / oneDayInSec);
                    let timeLeft = diff;
                    if (daysLeft >= 1) {
                        timeLeft = diff - daysLeft * oneDayInSec;
                    }
                    data.inactivity = {
                        daysLeft: daysLeft,
                        timeLeft: timeLeft,
                        dropDelay: `${daysLeft}d, ${this._utilitiesService.secondsToDuration(timeLeft)}`,
                        dropDate: Math.floor(exp.getTime() / 1000),
                    };
                    data.raids = [];
                    data.raidsInfo = { variationAvg: 0, variationSum: 0 };
                    data.stat = {} as HWMemberStat;
                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
                    let index = guildData.membersStat.findIndex((stat) => (stat as any).userId === data.id);
                    if (index !== -1) {
                        // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
                        const { userId, ...memberStatWithoutUserId } = guildData.membersStat[index] as any;
                        Object.assign(data.stat, memberStatWithoutUserId);
                    }
                    index = guildStatistics.stat.findIndex((stat) => stat.id === data.id);
                    if (index !== -1) {
                        // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
                        const { id, ...weekStatSource } = guildStatistics.stat[index] as any;
                        const stat: HWWeekStat = {} as HWWeekStat;
                        Object.assign(stat, weekStatSource);
                        data.weekStat = stat;
                        data.adventureSum = guildStatistics.stat[index].adventureStat.reduce(
                            (acc: number, cur: number) => acc + cur,
                            0,
                        );
                        data.clanGiftsSum = guildStatistics.stat[index].clanGifts.reduce(
                            (acc: number, cur: number) => acc + cur,
                            0,
                        );
                        data.clanWarSum = guildStatistics.stat[index].clanWarStat.reduce(
                            (acc: number, cur: number) => acc + cur,
                            0,
                        );
                    } else {
                        data.weekStat = {} as HWWeekStat;
                        data.adventureSum = 0;
                        data.clanGiftsSum = 0;
                        data.clanWarSum = 0;
                    }
                    data.score = data.stat.dungeonActivitySum + data.stat.activitySum + data.stat.prestigeSum;
                    data.warGifts = ((clan.giftsCount / 2) * ((data.clanWarSum * 10) / 100)) / 20;
                    data.scoreGifts = 0;
                    data.rewards = 0;
                    return data;
                });
                return guildMembers;
            }),
        );
    }
}
