package ru.bitel.bgbilling.modules.tv.dyn.moovi;

import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;

import jakarta.annotation.Resource;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.JSONException;
import org.json.JSONObject;

import ru.bitel.bgbilling.apps.tv.access.TvAccess;
import ru.bitel.bgbilling.common.BGException;
import ru.bitel.bgbilling.kernel.container.managed.ServerContext;
import ru.bitel.bgbilling.kernel.event.EventProcessor;
import ru.bitel.bgbilling.modules.tv.common.bean.TvAccount;
import ru.bitel.bgbilling.modules.tv.common.event.access.manage.TvDeviceManageEvent;
import ru.bitel.bgbilling.modules.tv.dyn.JsonClient;
import ru.bitel.bgbilling.modules.tv.dyn.JsonClient.Method;
import ru.bitel.bgbilling.modules.tv.server.bean.TvAccountDao;
import ru.bitel.bgbilling.modules.tv.server.runtime.TvAccountRuntime;
import ru.bitel.bgbilling.server.util.Setup;
import ru.bitel.common.ParameterMap;
import ru.bitel.common.Utils;
import ru.bitel.oss.systems.inventory.resource.common.bean.Device;
import ru.bitel.oss.systems.inventory.resource.common.bean.DeviceType;
import ru.bitel.oss.systems.inventory.resource.common.dm.DeviceManager;
import ru.bitel.oss.systems.inventory.resource.common.dm.DeviceManagerAdapter;

public class MooviDeviceManager
    extends DeviceManagerAdapter
    implements DeviceManager
{
    private static final Logger logger = LogManager.getLogger();

    @Resource( name = "access" )
    private TvAccess access;

    private String account;
    private String password;

    private JsonClient jsonClient;

    @Override
    public Object init( Setup setup, int moduleId, Device<?, ?> tvDevice, DeviceType deviceType, ParameterMap config )
        throws Exception
    {
        super.init( setup, moduleId, tvDevice, deviceType, config );

        this.account = config.get( "om.login", config.get( "moovi.api.login", tvDevice.getUsername() ) );
        this.password = config.get( "om.password", config.get( "moovi.api.password", tvDevice.getPassword() ) );

        this.jsonClient = new JsonClient( new URL( "https://api.billing.moovi-iptv.ru/" ), null, null );
        this.jsonClient.setBasicAuth( false );

        return null;
    }

    @Override
    public Object destroy()
        throws Exception
    {
        return null;
    }

    @Override
    public Object connect()
        throws Exception
    {
        return super.connect();
    }

    @Override
    public Object disconnect()
        throws Exception
    {
        if( jsonClient != null )
        {
            jsonClient.disconnect();
        }

        return super.disconnect();
    }

    /**
     * Обработка задания - отправки сообщения.
     * 
     * @param e
     * @return
     * @throws JSONException
     * @throws IOException
     * @throws BGException
     */
    public Object addUserMessage( TvDeviceManageEvent e )
        throws JSONException, IOException, BGException
    {
        String message = e.getParams().get( "message" );
        if( Utils.notBlankString( message ) )
        {
            logger.info( "Message is empty" );
            return "Сообщение не указано.";
        }

        TvAccountRuntime tvAccountRuntime = access.getTvAccountRuntimeMap().get( e.getAccountId() );
        if( tvAccountRuntime == null )
        {
            logger.info( "TvAccountRuntime not found with id: " + e.getAccountId() );
            return "Аккаунт не найден.";
        }

        if( tvAccountRuntime.getTvAccount().getParentId() > 0 )
        {
            logger.error( "Message sent to child account with id: " + e.getAccountId() );
            return "Нельзя отправить сообщение дочернему аккаунту.";
        }

        long[] mooviAccountId = MooviOrderManager.parseMooviAccountId( tvAccountRuntime.getTvAccount() );
        if( mooviAccountId == null )
        {
            logger.info( "TvAccountRuntime not synchronized with MW (id not found)" );
            return "Аккаунт не синхронизирован (внешний ID не найден).";
        }

        JSONObject addUserMessage = new JSONObject();
        addUserMessage.put( "account", this.account );
        addUserMessage.put( "password", this.password );

        addUserMessage.put( "message", mooviAccountId[0] );
        addUserMessage.put( "delivery_time_start", "now" );
        addUserMessage.put( "delivery_time_end", "+1 day" );
        addUserMessage.put( "recipient_users", Arrays.asList( mooviAccountId[0] ) );

        JSONObject result = jsonClient.newRequest()
            .setMethod( Method.post )
            .setResource( "addUserMessage" )
            .setHeader( "Content-Type", "application/json" )
            .setHeader( "Accept", "*/*" )
            .setBody( addUserMessage )
            .execute()
            .getJsonObject();

        return result;
    }

    /**
     * Отправка сообщения абоненту в приложение.
     * 
     * @param moduleId  ID модуля TV.
     * @param deviceId  ID устройства - Moovi в дереве устройств.
     * @param accountId ID аккаунта.
     * @param message   сообщение.
     * @throws BGException
     */
    public static void addUserMessage( int moduleId, int deviceId, int accountId, String message )
        throws BGException
    {
        TvDeviceManageEvent e = new TvDeviceManageEvent( moduleId, 0, deviceId, "addUserMessage", accountId, 0 );
        EventProcessor.getInstance().publish( e );
    }

    /**
     * Отправка сообщения абоненту в приложение. Метод предназначен для вызова из Sender плагина Dispatch.
     * 
     * @param moduleId    ID модуля TV.
     * @param contractId  ID договора.
     * @param title       тема сообщения.
     * @param messageBody сообщение.
     * @throws BGException
     */
    public static void addUserMessage( final int moduleId, final int contractId, String title, String messageBody )
        throws BGException
    {
        final ServerContext context = ServerContext.get();

        final List<TvAccount> tvAccountList;
        try( TvAccountDao tvAccountDao = new TvAccountDao( context.getConnection(), moduleId ) )
        {
            tvAccountList = tvAccountDao.list( contractId );
            if( tvAccountList == null || tvAccountList.size() == 0 )
            {
                return;
            }
        }

        if( Utils.notBlankString( title ) )
        {
            messageBody = title + ": " + messageBody;
        }

        for( TvAccount tvAccount : tvAccountList )
        {
            if( tvAccount.getParentId() > 0 )
            {
                continue;
            }

            addUserMessage( moduleId, tvAccount.getDeviceId(), tvAccount.getId(), messageBody );
        }
    }
}
