import { remote } from 'electron';
import * as fs from 'fs';

import {
    Component,
    NgZone,
} from '@angular/core';

import { ApiService } from 'jslib/abstractions/api.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { MessagingService } from 'jslib/abstractions/messaging.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { SyncService } from 'jslib/abstractions/sync.service';
import { TokenService } from 'jslib/abstractions/token.service';

import { PremiumComponent as BasePremiumComponent } from 'jslib/angular/components/premium.component';

import { PaymentMethodType } from 'jslib/enums/paymentMethodType';

import { IapCheckRequest } from 'jslib/models/request/iapCheckRequest';

import { Utils } from 'jslib/misc/utils';

const AppStorePremiumPlan = 'premium_annually';

@Component({
    selector: 'app-premium',
    templateUrl: 'premium.component.html',
})
export class PremiumComponent extends BasePremiumComponent {
    purchasePromise: Promise<any>;
    restorePromise: Promise<any>;
    canMakeMacAppStorePayments = false;
    appStoreFormattedPrice = '$14.99';
    canRestorePurchase = false;

    private makingPremiumAfterPurchase = false;

    constructor(i18nService: I18nService, platformUtilsService: PlatformUtilsService,
        tokenService: TokenService, apiService: ApiService,
        private ngZone: NgZone, private messagingService: MessagingService,
        private syncService: SyncService) {
        super(i18nService, platformUtilsService, tokenService, apiService);
    }

    async ngOnInit() {
        await super.ngOnInit();
        const isMacAppStore = this.platformUtilsService.isMacAppStore();
        if (isMacAppStore) {
            this.canMakeMacAppStorePayments = remote.inAppPurchase.canMakePayments();
        }
        if (this.isPremium || !isMacAppStore || !this.canMakeMacAppStorePayments) {
            return;
        }
        const pricePromise = new Promise((resolve) => {
            remote.inAppPurchase.getProducts([AppStorePremiumPlan], (products) => {
                this.ngZone.run(() => {
                    if (products == null || !Array.isArray(products) || products.length === 0) {
                        return;
                    }
                    this.appStoreFormattedPrice = products[0].formattedPrice;
                    resolve();
                });
            });
        });
        this.setCanRestorePurchase();
        remote.inAppPurchase.on('transactions-updated', (event, transactions) => {
            this.ngZone.run(async () => {
                if (transactions == null || !Array.isArray(transactions)) {
                    return;
                }
                // Check each transaction.
                transactions.forEach(async (transaction) => {
                    const payment = transaction.payment;
                    switch (transaction.transactionState) {
                        case 'purchasing':
                            // tslint:disable-next-line
                            console.log(`Purchasing ${payment.productIdentifier}...`);
                            break;
                        case 'purchased':
                            // tslint:disable-next-line
                            console.log(`${payment.productIdentifier} purchased.`);
                            if (this.makingPremiumAfterPurchase || payment.productIdentifier !== AppStorePremiumPlan) {
                                return;
                            }
                            try {
                                this.makingPremiumAfterPurchase = true;
                                await this.makePremium(false);
                            } catch { }
                            this.makingPremiumAfterPurchase = false;
                            // Finish the transaction.
                            remote.inAppPurchase.finishTransactionByDate(transaction.transactionDate);
                            break;
                        case 'failed':
                            // tslint:disable-next-line
                            console.log(`Failed to purchase ${payment.productIdentifier}. ` +
                                `${transaction.errorCode} = ${transaction.errorMessage}`);
                            if (transaction.errorCode !== 2) {
                                this.platformUtilsService.showToast('error', null, transaction.errorMessage);
                            }
                            // Finish the transaction.
                            remote.inAppPurchase.finishTransactionByDate(transaction.transactionDate);
                            break;
                        case 'restored':
                            // tslint:disable-next-line
                            console.log(`The purchase of ${payment.productIdentifier} has been restored.`);
                            break;
                        case 'deferred':
                            // tslint:disable-next-line
                            console.log(`The purchase of ${payment.productIdentifier} has been deferred.`);
                            break;
                        default:
                            break;
                    }
                });
            });
        });
    }

    async purchase() {
        if (this.isPremium || !this.canMakeMacAppStorePayments) {
            await super.purchase();
            return;
        }
        try {
            const request = new IapCheckRequest();
            request.paymentMethodType = PaymentMethodType.AppleInApp;
            this.purchasePromise = this.apiService.postIapCheck(request);
            await this.purchasePromise;
            remote.inAppPurchase.purchaseProduct(AppStorePremiumPlan, 1, (isValid) => {
                if (!isValid) {
                    // TODO?
                }
            });
        } catch { }
    }

    async restore() {
        if (this.isPremium || !this.canMakeMacAppStorePayments) {
            return;
        }
        let makePremium = false;
        try {
            const request = new IapCheckRequest();
            request.paymentMethodType = PaymentMethodType.AppleInApp;
            this.restorePromise = this.apiService.postIapCheck(request);
            await this.restorePromise;
            makePremium = true;
        } catch { }
        if (makePremium) {
            await this.makePremium(true);
        }
    }

    async manage() {
        if (!this.canMakeMacAppStorePayments || this.getReceiptUrl() == null) {
            await super.manage();
            return;
        }
        const confirmed = await this.platformUtilsService.showDialog(this.i18nService.t('premiumManageAlertAppStore'),
            this.i18nService.t('premiumManage'), this.i18nService.t('yes'), this.i18nService.t('cancel'));
        if (confirmed) {
            this.platformUtilsService.launchUri('itms-apps://apps.apple.com/account/subscriptions');
        }
    }

    private async makePremium(restore: boolean) {
        const receiptUrl = this.getReceiptUrl();
        const receiptBuffer = fs.readFileSync(receiptUrl);
        const receiptB64 = Utils.fromBufferToB64(receiptBuffer);
        const fd = new FormData();
        fd.append('paymentMethodType', '6');
        fd.append('paymentToken', receiptB64);
        fd.append('additionalStorageGb', '0');
        try {
            const p = this.apiService.postPremium(fd).then((paymentResponse) => {
                if (paymentResponse.success) {
                    return this.finalizePremium();
                }
            });
            if (restore) {
                this.restorePromise = p;
                await this.restorePromise;
            } else {
                this.purchasePromise = p;
                await this.purchasePromise;
            }
        } catch { }
    }

    private async finalizePremium() {
        await this.apiService.refreshIdentityToken();
        await this.syncService.fullSync(true);
        this.platformUtilsService.showToast('success', null, this.i18nService.t('premiumUpdated'));
        this.messagingService.send('purchasedPremium');
        this.isPremium = this.tokenService.getPremium();
        this.setCanRestorePurchase();
    }

    private setCanRestorePurchase() {
        if (!this.isPremium && this.canMakeMacAppStorePayments) {
            const receiptUrl = this.getReceiptUrl();
            this.canRestorePurchase = receiptUrl != null;
        } else {
            this.canRestorePurchase = false;
        }
    }

    private getReceiptUrl(): string {
        const receiptUrl = remote.inAppPurchase.getReceiptURL();
        if (receiptUrl != null) {
            return fs.existsSync(receiptUrl) ? receiptUrl : null;
        }
        return null;
    }
}
