package ru.bitel.bgbilling.modules.inet.dyn.ip.handler;

import java.util.List;

import ru.bitel.bgbilling.common.BGMessageException;
import ru.bitel.bgbilling.kernel.directory.api.common.bean.Directory;
import ru.bitel.bgbilling.kernel.network.radius.RadiusPacket;
import ru.bitel.bgbilling.modules.inet.common.bean.InetServ;
import ru.bitel.bgbilling.modules.inet.common.bean.InetServType;
import ru.bitel.bgbilling.modules.inet.common.bean.InetServTypeIPMode;
import ru.bitel.bgbilling.modules.inet.common.service.InetSessionService;
import ru.bitel.bgbilling.modules.inet.server.bean.InetServDao;
import ru.bitel.bgbilling.modules.inet.server.bean.InetSessionDao;
import ru.bitel.bgbilling.modules.inet.server.ip.AbstractInetServIpHandler;
import ru.bitel.bgbilling.modules.inet.server.ip.InetServIpData;
import ru.bitel.bgbilling.modules.inet.server.ip.InetServIpHandler;
import ru.bitel.bgbilling.modules.inet.server.ip.InetServIpUtils;
import ru.bitel.common.TimeUtils;
import ru.bitel.common.inet.IpAddress;
import ru.bitel.oss.systems.inventory.resource.common.bean.IpResource;
import ru.bitel.oss.systems.inventory.resource.common.bean.IpResourceSubscription;
import ru.bitel.oss.systems.inventory.resource.common.service.ResourceService;

public class SimpleIPv4Handler
	extends AbstractInetServIpHandler
	implements InetServIpHandler
{
    @Override
    public void checkAddress( InetServ inetServ, InetServType servType )
        throws BGMessageException
    {
        InetServTypeIPMode ipv4Mode = getIPv4Mode( servType );
        if ( ipv4Mode.isSelectStatic() && !(ipv4Mode.isSelectNo() || ipv4Mode.isSelectDynamic()) )
        {
            if ( inetServ.getAddressFrom() == null )
            {
                throw new BGMessageException( "Не указан Framed-IP-Address" );
            }
        }
    }
    
    @Override
    public void setAddress( InetServ inetServ, InetServType servType, InetServ oldInetServ, int subscriberId, String subscriberTitle )
        throws Exception
    {
        InetServTypeIPMode ipv4Mode = getIPv4Mode( servType );
        if ( ipv4Mode.isSelectStatic() && !(ipv4Mode.isSelectNo() || ipv4Mode.isSelectDynamic()) )
        {
            boolean needSubscription = oldInetServ == null || 
                    ( !IpAddress.equals( oldInetServ.getAddressFrom(), inetServ.getAddressFrom() ) || 
                      !( ( oldInetServ.getAddressTo() == null && inetServ.getAddressTo() == null ) || IpAddress.equals( oldInetServ.getAddressTo(), inetServ.getAddressTo() ) ) || 
                      !( ( oldInetServ.getDateFrom() == null && inetServ.getDateFrom() == null ) || TimeUtils.dateEqual( oldInetServ.getDateFrom(), inetServ.getDateFrom() ) ) || 
                      !( ( oldInetServ.getDateTo() == null && inetServ.getDateTo() == null) || TimeUtils.dateEqual( oldInetServ.getDateTo(), inetServ.getDateTo() ) ) );
    
            ResourceService resourceService = context.getService( ResourceService.class, moduleId );
            List<Integer> ipResourceCategoryIds = inetServService.ipResourceCategoryIds( inetServ.getDeviceId(), inetServ.getInterfaceId(), inetServ.getTypeId() );
            
            // проверяем есть ли этот ресурс в этой категории (на случай если
            // категорию на устройстве поменяли, нужно менять подписку)
            if ( oldInetServ != null )
            {
                boolean need = true; 
                for ( IpResource ipResource : resourceService.ipResourceList( ipResourceCategoryIds ) )
                {
                    if ( oldInetServ.getIpResourceId() == ipResource.getId() )
                    {
                        need = false;
                        break;
                    }
                }
                needSubscription |= need; 
            }
            
            if ( needSubscription )
            {
                // если поменялся адрес на сервисе, отменяем подписку на старый адрес
                if ( oldInetServ != null && oldInetServ.getAddressFrom() != null )
                {
                    resourceService.ipResourceUnsubscribe( subscriberId, oldInetServ.getIpResourceSubscriptionId(), oldInetServ.getAddressFrom(), oldInetServ.getAddressTo() );
                    inetServ.setIpResourceId( 0 );
                    inetServ.setIpResourceSubscriptionId( 0 );
                }
    
                // подписка на новый адрес
                IpResourceSubscription subscription = resourceService.ipResourceSubscribe( subscriberId, subscriberTitle, ipResourceCategoryIds, 0, inetServ.getAddressFrom(), inetServ.getAddressFrom(), inetServ.getDateFrom(), inetServ.getDateTo() );
                inetServ.setIpResourceId( subscription.getIpResourseId() );
                inetServ.setIpResourceSubscriptionId( subscription.getId() );
    
                try ( InetServDao inetServDao = new InetServDao( context.getConnectionSet().getConnection(), moduleId ) )
                {
                    inetServDao.updateIpResource( inetServ.getId(), inetServ.getIpResourceId(), inetServ.getIpResourceSubscriptionId() );
                }
                
                final InetSessionService inetSessionService = context.getService( InetSessionService.class, moduleId );
                final Directory<InetServType> servTypeDirectory = context.newDirectory( InetServType.class, moduleId );
                final InetSessionDao inetSessionDao = new InetSessionDao( context.getConnectionSet().getConnection(), moduleId );
                InetServIpUtils.closeConnectionsWithIntersectionIP( inetServ, inetSessionDao, servTypeDirectory, inetSessionService, moduleId );
            }
        }
    }
    
    @Override
    public boolean setRadiusIp( InetServIpData inetServIpData, RadiusPacket request, RadiusPacket response )
    {
        InetServTypeIPMode ipv4Mode = getIPv4Mode( inetServIpData.getInetServTypeRuntime().inetServType );
        InetServ inetServ = inetServIpData.getInetServ(); 
        if ( ipv4Mode.isSelectStatic() && inetServ.getAddressFrom() != null )
        {
            setFramedIPAddress( inetServIpData.getRadiusListenerWorker(), response, inetServ.getIpResourceId(), inetServ.getAddressFrom() );
            return true;
        }
        else if ( ipv4Mode.isSelectDynamic() )
        {
            IpResult result = tryReserveIPv4FromPool( inetServIpData, request );
            if ( result.getIpAddress() != null )
            {
                setFramedIPAddress( inetServIpData.getRadiusListenerWorker(), response, result.getIpResourceId(), result.getIpAddress() );
                return true;
            }
            else if ( ipv4Mode.isSelectNo() )
            {
                return true;
            }
        }
        else if ( ipv4Mode.isSelectNo() )
        {
            return true;
        }
        return false;
    }
}