package ru.bitel.bgbilling.modules.tv.dyn.infomir.ministra;

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

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;

import javax.annotation.Resource;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

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

    private MinistraConfig config;

    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.config = new MinistraConfig( tvDevice, config );

        URL url = this.config.getUrl();

        logger.info( "URL: " + url );

        this.jsonClient = new JsonClient( url, this.config.getLogin(), this.config.getPassword() );

        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 stbMessage( TvDeviceManageEvent e )
        throws JSONException, IOException, BGException
    {
        String message = e.getParams().get( "message" );
        if( Utils.notBlankString( message ) )
        {
            logger.info( "Message is empty" );
            return null;
        }

        TvAccountRuntime tvAccountRuntime = access.getTvAccountRuntimeMap().get( e.getAccountId() );
        if( tvAccountRuntime == null )
        {
            logger.info( "TvAccountRuntime not found with id: " + e.getAccountId() );
            return null;
        }

        if( tvAccountRuntime.getTvAccount().getParentId() > 0 )
        {
            logger.error( "Message sent to child account with id: " + e.getAccountId() );
            return null;
        }

        // аккаунт - логин или ID родительского аккаунта
        final String accountNumber = config.getAccountNumber( tvAccountRuntime.getTvAccount() );

        String ttl = e.getParams().get( "ttl" );

        Map<String, Object> params = new HashMap<>();
        params.put( "msg", message );

        if( Utils.notBlankString( ttl ) )
        {
            params.put( "ttl", ttl );
        }

        try
        {
            return jsonClient.request( Method.post, null, "stb_msg", accountNumber, params );
        }
        catch( Exception ex )
        {
            logger.error( ex.getMessage(), ex );
            return ex.getMessage();
        }
    }

    /**
     * Отправка сообщения абоненту на STB.
     * 
     * @param moduleId  ID модуля TV.
     * @param deviceId  ID устройства - Ministra в дереве устройств.
     * @param accountId ID аккаунта.
     * @param message   сообщение.
     * @throws BGException
     */
    public static void stbMessage( int moduleId, int deviceId, int accountId, String message )
        throws BGException
    {
        TvDeviceManageEvent e = new TvDeviceManageEvent( moduleId, 0, deviceId, "message", accountId, 0 );
        EventProcessor.getInstance().publish( e );
    }
    
    /**
     * Отправка сообщения абоненту на STB. Метод предназначен для вызова из Sender плагина Dispatch.
     * @param moduleId ID модуля TV.
     * @param contractId ID договора.
     * @param title тема сообщения.
     * @param messageBody сообщение.
     * @throws BGException
     */
    public static void stbMessage( 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;
            }

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