package com.alphawallet.app.service;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.text.TextUtils;

import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;

import com.alphawallet.app.C;
import com.alphawallet.app.R;
import com.alphawallet.app.entity.Transaction;
import com.alphawallet.app.entity.TransactionType;
import com.alphawallet.app.entity.tokens.Token;
import com.alphawallet.app.entity.transactions.TransferEvent;
import com.alphawallet.app.repository.PreferenceRepositoryType;
import com.alphawallet.app.ui.TransactionDetailActivity;
import com.alphawallet.app.util.BalanceUtils;
import com.alphawallet.app.util.Utils;

import java.util.Locale;

public class TransactionNotificationService
{
    private static final String CHANNEL_ID = "transactions_channel";
    private static final String CHANNEL_NAME = "Transactions";
    private final Context context;
    private final PreferenceRepositoryType preferenceRepository;

    public TransactionNotificationService(
        Context context,
        PreferenceRepositoryType preferenceRepositoryType
    )
    {
        this.context = context;
        this.preferenceRepository = preferenceRepositoryType;
    }

    public void showNotification(Transaction tx, Token t, TransferEvent te)
    {
        int id = tx.hash != null ? tx.hash.hashCode() : 0;

        PendingIntent pendingIntent
            = PendingIntent.getActivity(
            context, id, buildIntent(tx, t),
            PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);

        NotificationManager notificationManager =
            (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) // Oreo and above requires notification channels
        {
            NotificationChannel notificationChannel =
                new NotificationChannel(
                    CHANNEL_ID,
                    CHANNEL_NAME,
                    NotificationManager.IMPORTANCE_HIGH
                );

            notificationManager.createNotificationChannel(notificationChannel);
        }

        Notification n = createNotification(pendingIntent, tx, t, te);
        if (n != null)
        {
            notificationManager.notify(id, n);
        }
    }

    public Notification createNotification(PendingIntent intent, Transaction tx, Token t, @Nullable TransferEvent te)
    {
        String walletAddress = preferenceRepository.getCurrentWalletAddress();

        boolean defaultCase =
            !preferenceRepository.isWatchOnly() &&
                tx.timeStamp > preferenceRepository.getLoginTime(walletAddress) &&
                preferenceRepository.isTransactionNotificationsEnabled(walletAddress);

        if (te == null)
        {
            TransactionType txType = t.getTransactionType(tx);
            boolean receivedBaseToken =
                (txType.equals(TransactionType.RECEIVED) ||
                    txType.equals(TransactionType.RECEIVE_FROM)) &&
                    tx.to.equalsIgnoreCase(walletAddress);

            if (defaultCase && receivedBaseToken)
            {
                return buildNotification(
                    intent,
                    context.getString(R.string.received),
                    t.getTransactionResultValue(tx),
                    tx.from);
            }
        }
        else
        {
            if (defaultCase && isRecipient(walletAddress, te.valueList))
            {
                boolean isMintEvent = isMintEvent(te.valueList);
                return buildNotification(
                    intent,
                    isMintEvent ?
                        context.getString(R.string.minted) :
                        context.getString(R.string.received),
                    getReadableValue(t, te.tokenValue) + " " + t.getSymbol(),
                    isMintEvent ?
                        "" :
                        tx.from
                );
            }
        }

        return null;
    }

    private Intent buildIntent(Transaction tx, Token t)
    {
        Intent intent = new Intent(context, TransactionDetailActivity.class);
        intent.putExtra(C.EXTRA_TXHASH, tx.hash);
        intent.putExtra(C.EXTRA_CHAIN_ID, t.tokenInfo.chainId);
        intent.putExtra(C.EXTRA_ADDRESS, t.getAddress());
        intent.putExtra(C.FROM_NOTIFICATION, true);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);

        return intent;
    }

    private Notification buildNotification(PendingIntent pendingIntent, String event, String value, String fromAddress)
    {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_logo)
            .setAutoCancel(true)
            .setVibrate(new long[]{1000, 1000, 1000, 1000, 1000})
            .setOnlyAlertOnce(true)
            .setContentIntent(pendingIntent)
            .setContentTitle(getTitle(event, value))
            .setContentText(getBody(value, fromAddress))
            .setStyle(new NotificationCompat.BigTextStyle()
                .bigText(getBody(value, fromAddress))
            );

        return builder.build();
    }

    private String getTitle(String event, String value)
    {
        return event + " " + value;
    }

    private String getBody(String value, String fromAddress)
    {
        if (TextUtils.isEmpty(fromAddress))
        {
            return context.getString(R.string.notification_message_incoming_token,
                Utils.formatAddress(preferenceRepository.getCurrentWalletAddress()),
                value
            );
        }
        else
        {
            return context.getString(R.string.notification_message_incoming_token_with_recipient,
                Utils.formatAddress(preferenceRepository.getCurrentWalletAddress()),
                value,
                Utils.formatAddress(fromAddress)
            );
        }
    }

    private boolean isMintEvent(String input)
    {
        String searchText = "from,address,";
        int startIndex = input.indexOf(searchText) + searchText.length();
        int endIndex = input.indexOf(",", startIndex);
        String from = input.substring(startIndex, endIndex);
        return from.equalsIgnoreCase(C.BURN_ADDRESS);
    }

    private boolean isRecipient(String walletAddress, String input)
    {
        String validationString = "to,address," + walletAddress.toLowerCase(Locale.ROOT);
        return input.toLowerCase(Locale.ROOT).contains(validationString);
    }

    private String getReadableValue(Token t, String tokenValue)
    {
        if (t.isERC20())
        {
            return BalanceUtils.getScaledValue(tokenValue, t.tokenInfo.decimals);
        }
        else
        {
            return "#" + tokenValue;
        }
    }
}
