import { AfterLoad, Column, Entity, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
import { getRepository } from 'typeorm';
import { BankTransactionEntity } from './bank-transaction.entity';
import { BankEntity } from './bank.entity';
import { CharacterEntity } from './character.entity';
import { FactionEntity } from './faction.entity';
import { CompanyEntity } from './company.entity';
import { companySystem } from '../features/company';
import { LoanEntity } from './loan.entity';
import { MazePayAccountEntity } from './maze-pay-account.entity';

@Entity('bank_accounts')
export class BankAccountEntity {
    @PrimaryGeneratedColumn() id: number;
    @Column({ unique: true, length: 10 }) number: string;
    @Column({ type: 'int' }) bank_id: number;
    @Column({ type: 'int', default: 0 }) balance: number;
    @Column({ type: 'int', default: null }) character_id: number | null;
    @Column({ type: 'int', default: null }) company_id: number | null;
    @Column({ type: 'int', default: null }) faction_id: number | null;
    @Column({ type: 'datetime' }) created: Date;

    @OneToMany(() => BankTransactionEntity, (transaction) => transaction.bankAccount)
    transactions: BankTransactionEntity[];

    @ManyToOne(() => BankEntity, (bank) => bank.accounts)
    @JoinColumn({ name: 'bank_id' })
    bank: BankEntity;

    @ManyToOne(() => CompanyEntity, (company) => company.bankAccounts)
    @JoinColumn({ name: 'company_id' })
    company: CompanyEntity;

    @ManyToOne(() => CharacterEntity, (character) => character.bankAccounts)
    @JoinColumn({ name: 'character_id' })
    character: CharacterEntity;

    @ManyToOne(() => FactionEntity, (faction) => faction.bankAccounts)
    @JoinColumn({ name: 'faction_id' })
    faction: FactionEntity;

    @OneToMany(() => LoanEntity, (loan) => loan.bankAccount)
    loans: LoanEntity[];

    @OneToMany(() => MazePayAccountEntity, (mpae) => mpae.bankAccount)
    mazePayAccounts: MazePayAccountEntity[];

    iban?: string;

    historyForPreview: number[] = [];

    name: string;

    @AfterLoad()
    afterLoad(): void {
        this.iban = this.getIban(false);
    }

    async generateHistoryForPreview(): Promise<void> {
        const recentTransactions = await getRepository(BankTransactionEntity)
            .createQueryBuilder()
            .where('DATE(`date`) > DATE_SUB(NOW(), INTERVAL 10 DAY) AND bank_account_id = :id', {
                id: this.id,
            })
            .orderBy({
                date: 'DESC',
            })
            .getMany();

        const date = new Date();

        this.historyForPreview = [this.balance];
        let currentBalance = this.balance;

        for (let i = 0; i < 9; i++) {
            const amountInDate = recentTransactions
                .filter((rt) => {
                    return new Date(rt.date).toDateString() === date.toDateString();
                })
                .reduce((total, rt) => total - rt.amount, currentBalance);

            this.historyForPreview.unshift(amountInDate);

            currentBalance = amountInDate;
            date.setDate(date.getDate() - 1);
        }
    }

    getIban(pretty: boolean, bold?: boolean): string {
        const statePrefix = 'LS';
        let accountType = '10'; // personal

        if (this.faction_id) {
            accountType = '20';
        } else if (this.company_id) {
            accountType = '30';
        }

        if (pretty) {
            if (bold) {
                return `${statePrefix}${accountType} <strong>${this.bank_id}</strong> 0000 00<strong>${this.number.slice(0, 2)} ${this.number.slice(
                    2,
                    6,
                )} ${this.number.slice(6)}</strong>`;
            }
            return `${statePrefix}${accountType} ${this.bank_id} 0000 00${this.number.slice(0, 2)} ${this.number.slice(2, 6)} ${this.number.slice(6)}`;
        }

        return `${statePrefix}${accountType}${this.bank_id}000000${this.number}`;
    }

    async cacheName(): Promise<void> {
        this.name = await this.getName();
    }

    async getName(): Promise<string> {
        if (this.character_id) {
            const character = await getRepository(CharacterEntity).findOne({
                id: this.character_id,
            });
            if (character) {
                return character.getIcName(false);
            }
            return this.getIban(true);
        }

        if (this.faction_id) {
            const faction = await getRepository(FactionEntity).findOne({
                id: this.faction_id,
            });
            if (faction) {
                return faction.name;
            }
            return this.getIban(true);
        }

        if (this.company_id) {
            const company = companySystem.companies.find((c) => c.id === this.company_id);
            if (company) {
                return company.name;
            }
        }

        return this.getIban(true);
    }

    getTypeName(): string {
        if (this.character_id) {
            return 'Personal Account';
        }

        if (this.company_id) {
            return 'Business Account';
        }

        if (this.faction_id) {
            return 'Agency Account';
        }

        return 'Unknown Account';
    }
}
