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

import ru.bitel.bgbilling.modules.tv.common.bean.TvAccount;
import ru.bitel.common.ParameterMap;
import ru.bitel.common.Utils;
import ru.bitel.oss.systems.inventory.resource.common.bean.Device;

import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

public class MinistraConfig
{
    /**
     * Изначальный вариант - если логин родительского аккаунта не пустой, то используется его значение, иначе - tv_account.id.
     */
    public static final int ACCOUNT_MODE_DEFAULT = 0;

    /**
     * В качестве account_number используется tv_account.id родительского аккаунта.
     */
    public static final int ACCOUNT_MODE_ID = 1;

    /**
     * В качестве account_number используется Идентификатор родительского аккаунта. Если он пустой, то используется tv_account.id родительского аккаунта.
     */
    public static final int ACCOUNT_MODE_IDENTIFIER = 2;

    private final URL url;
    private final String login;
    private final String password;

    /**
     * Форматирование tv_account.id для account_number, если поле логин родительского аккаунта пустое.
     */
    private final DecimalFormat accountNumberFormat;

    private int accountNumberMode = ACCOUNT_MODE_DEFAULT;

    /**
     * Форматирование tv_account.id для login, если поле логин аккаунта-stb пустое.
     */
    private final DecimalFormat loginFormat;

    /**
     * Полная или частичная синхронизация продуктов.
     */
    private final boolean productSyncMode;

    /**
     * Идентификатор тарифного плана по умолчанию.
     */
    private final String tariffDefault;

    /**
     * Определение продукта-тарифа по родительским узлам.
     */
    private final Set<Integer> tariffProductParentIds;

    /**
     * Определение продукта-тарифа по списковому атрибуту.
     */
    private final int tariffProductEntitySpecAttrId;

    /**
     * Определение продукта-тарифа по списковому атрибуту.
     */
    private final int tariffProductEntityAttrValue;

    public MinistraConfig( Device<?, ?> tvDevice, ParameterMap config )
        throws MalformedURLException
    {
        String host = null;
        int port = 0;

        List<InetSocketAddress> addressList = tvDevice.getHosts();
        if ( addressList.size() > 0 )
        {
            InetSocketAddress socketAddress = addressList.get( 0 );
            host = socketAddress.getHostName();
            port = socketAddress.getPort();
        }

        if ( Utils.isBlankString( host ) )
        {
            host = "undefined";
        }

        if ( port <= 0 )
        {
            port = 80;
        }

        this.url = URI.create( config.get( "om.url", config.get( "stalker.api.url", "http://" + host + ":" + port + "/stalker_portal/api/" ) ) ).toURL();

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

        String loginFormat = config.get( "om.login.format", config.get( "om.account.loginFormat", null ) );
        if ( Utils.notBlankString( loginFormat ) )
        {
            this.loginFormat = new DecimalFormat( loginFormat );
        }
        else
        {
            this.loginFormat = null;
        }

        String accountFormat = config.get( "om.accountNumber.format", config.get( "om.account.accountFormat", null ) );
        if ( Utils.notBlankString( accountFormat ) )
        {
            this.accountNumberFormat = new DecimalFormat( accountFormat );
        }
        else
        {
            this.accountNumberFormat = null;
        }

        this.accountNumberMode = config.getInt( "om.accountNumber.mode", ACCOUNT_MODE_DEFAULT );

        this.productSyncMode = config.getInt( "om.product.syncMode", 1 ) > 0;

        this.tariffDefault = config.get( "om.tariff.default", "10" );

        final Set<Integer> tariffProductParentIds = Utils.toIntegerSet( config.get( "om.tariff.product.parentIds", null ) );
        if ( tariffProductParentIds.size() == 0 )
        {
            this.tariffProductParentIds = null;
        }
        else
        {
            this.tariffProductParentIds = tariffProductParentIds;
        }

        this.tariffProductEntitySpecAttrId = config.getInt( "om.tariff.product.entitySpecAttrId", 0 );
        this.tariffProductEntityAttrValue = config.getInt( "om.tariff.product.entityAttrValue", 0 );
    }

    public URL getUrl()
    {
        return url;
    }

    public String getLogin()
    {
        return login;
    }

    public String getPassword()
    {
        return password;
    }

    public DecimalFormat getAccountNumberFormat()
    {
        return accountNumberFormat;
    }

    public int getAccountNumberMode()
    {
        return accountNumberMode;
    }

    public DecimalFormat getLoginFormat()
    {
        return loginFormat;
    }

    public boolean getProductSyncMode()
    {
        return productSyncMode;
    }

    public String getTariffDefault()
    {
        return tariffDefault;
    }

    public Set<Integer> getTariffProductParentIds()
    {
        return tariffProductParentIds;
    }

    public int getTariffProductEntitySpecAttrId()
    {
        return tariffProductEntitySpecAttrId;
    }

    public int getTariffProductEntityAttrValue()
    {
        return tariffProductEntityAttrValue;
    }

    /**
     * Получение account_number в соответствии с om.accountNumber.mode.
     * 
     * @param tvAccount
     * @return
     */
    public String getAccountNumber( final TvAccount tvAccount )
    {
        assert tvAccount.getParentId() <= 0;

        switch( getAccountNumberMode() )
        {
            case ACCOUNT_MODE_ID:
            {
                if ( getAccountNumberFormat() != null )
                {
                    return getAccountNumberFormat().format( tvAccount.getId() );
                }

                return String.valueOf( tvAccount.getId() );
            }

            case ACCOUNT_MODE_IDENTIFIER:
            {
                if ( Utils.notBlankString( tvAccount.getIdentifier() ) )
                {
                    return tvAccount.getIdentifier();
                }

                return String.valueOf( tvAccount.getId() );
            }

            case ACCOUNT_MODE_DEFAULT:
            default:
            {
                if ( Utils.notBlankString( tvAccount.getLogin() ) )
                {
                    return tvAccount.getLogin();
                }

                if ( getAccountNumberFormat() != null )
                {
                    return getAccountNumberFormat().format( tvAccount.getId() );
                }

                return String.valueOf( tvAccount.getId() );
            }
        }
    }

    private static final Pattern digits = Pattern.compile( "\\A[0-9]+\\z" );

    /**
     * Получение логина для STB. В типе аккаунта должно быть указано stb_type.
     * 
     * @param tvAccount
     * @return значение поля логин, если указано, иначе отформатированный tv_account.id
     */
    public String getLogin( final TvAccount tvAccount )
    {
        assert tvAccount.getParentId() > 0;

        if ( Utils.notBlankString( tvAccount.getLogin() ) )
        {
            if ( getLoginFormat() != null && digits.matcher( tvAccount.getLogin() ).matches() )
            {
                final long login = Utils.parseLong( tvAccount.getLogin(), -1 );
                if ( login > 0 )
                {
                    return getLoginFormat().format( login );
                }
            }

            return tvAccount.getLogin();
        }

        if ( getLoginFormat() != null )
        {
            return getLoginFormat().format( tvAccount.getId() );
        }

        return String.valueOf( tvAccount.getId() );
    }
}
