package ru.bitel.bgbilling.modules.voice.dyn.mediator.asterisk;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;

import au.com.bytecode.opencsv.CSVReader;
import ru.bitel.bgbilling.apps.voice.accounting.mediation.AbstractMediator;
import ru.bitel.bgbilling.apps.voice.accounting.mediation.VoiceRecord;
import ru.bitel.bgbilling.apps.voice.accounting.mediation.VoiceRecordProcessor;
import ru.bitel.bgbilling.common.BGException;
import ru.bitel.bgbilling.modules.voice.common.bean.VoiceDevice;
import ru.bitel.bgbilling.modules.voice.common.bean.VoiceDeviceType;
import ru.bitel.bgbilling.server.util.Setup;
import ru.bitel.common.ParameterMap;
import ru.bitel.common.TimeUtils;
import ru.bitel.common.Utils;

/**
 * Обработчик логов Asterisk. Берет файлы из подпапки "processed" в папке логов устройства.
 *
 * Эти файлы там лежат в таком виде:
 * processed/yyyymm/yyyymmdd/Master.csv-hhmmss
 * Где yyyy-год, mm-месяц, dd-день, hh-час, mm-минута, ss-секунда.
 *
 *Например
 * processed/201805/20180501/Master.csv-000510
 * processed/201805/20180501/Master.csv-001010
 * processed/201805/20180501/Master.csv-002012
 * processed/201805/20180501/Master.csv-002510
 * ...
 *
 И помещает их в 0-вой час каждого дня в биллинг.
 *
 */
public class AsteriskMediator
    extends AbstractMediator
{
    private String logPath;

    @Override
    public Object init( Setup setup, int moduleId, VoiceDevice device, VoiceDeviceType deviceType, ParameterMap config )
        throws Exception
    {
        this.logPath = device.getLogPath() + File.separatorChar + "processed";
        return super.init( setup, moduleId, device, deviceType, config );
    }

    @Override
    public void readHourDataLog( VoiceRecordProcessor processor, Date hour )
        throws Exception
    {
        //logger.info( "readHourDataLog!!!!!!!!!!"  );

        Calendar calHour = TimeUtils.convertDateToCalendar( hour );

        //обрабаьываем запросы только на нулевой час
        if ( calHour.get( Calendar.HOUR_OF_DAY ) != 0 )
        {
            return;
        }

        try
        {
            String fullPath = logPath + File.separatorChar +  TimeUtils.format( hour, "yyyyMM" )
                    + File.separatorChar + TimeUtils.format( hour, "yyyyMMdd" ) ;

            //TODO переделать чтение на java.nio2
            File dayDir = new File( fullPath );

            if ( !dayDir.exists() )
            {
                getLogger().warn( "log dir for {} is empty [dir={}]", hour, dayDir.toString() );
                return;
            }

            File files [] = dayDir.listFiles();
            if ( files == null )
            {
                return;
            }
            Arrays.sort( files );

            for ( File  logFile : files )
            {
                getLogger().info( "Process file: " + logFile.getName() );
                try (    InputStream is = new FileInputStream( logFile );
                BufferedReader reader = new BufferedReader( new InputStreamReader( is ), 128 * 1024 );
                //TODO он медленный, возможно потом переделать
                CSVReader csvReader = new CSVReader( reader, ',', '"' ) )
                {
                    String params[];
                    while( ( params = csvReader.readNext() ) != null )
                    {
                        if ( params.length == 18  )
                        {
                            /*if ( logger.isDebugEnabled() )
                            {
                                logger.debug( "LINE: " + line );
                            }*/
                            processLine( processor, params );
                        }
                        else
                        {
                            getLogger().warn( "Skip line: " + Arrays.stream( params ).reduce( "", (a,b) ->  a + "," +  b ) );
                        }
                    }
                }
                catch ( Throwable ex )
                {
                    throw new BGException( ex );
                }
            }
        }
        finally
        {
        }
    }

    protected VoiceRecord processLine( final VoiceRecordProcessor processor, final String[] params )
        throws InterruptedException
    {
        if ( params[17].contains( "NOT_ACCOUNT" ) || params[14].contains( "NO ANSWER" ) )
        {
            //игнорируем такие звонки.
            return null;
        }

        final VoiceRecord record = processor.next();

        fillRecord( params, record );
        
        return record;
    }

    protected static void fillRecord(  String[] params, VoiceRecord record )
    {
        String e164CallingStationId = params[1];
        String e164CalledStationId = params[2];

        e164CallingStationId = prepareNumber( e164CallingStationId );
        e164CalledStationId = prepareNumber( e164CalledStationId );

        record.trunkIncoming = params[5];
        record.callingStationId = params[1];
        record.calledStationId = params[2];
        record.trunkOutgoing = params[6];
        record.e164CallingStationId = e164CallingStationId;
        record.e164CalledStationId = e164CalledStationId;
        String dateTime = params[9];
        record.sessionStart = TimeUtils.parseDate( dateTime, "yyyy-MM-dd HH:mm:ss" );
        record.connectionDuration = Utils.parseInt( params[12], 0 );
        record.duration = Utils.parseInt( params[13], 0 );
    }

    private static String prepareNumber( String number )
    {
        if ( number.length() == 10 )
        {
            return 7 + number;
        }
        if ( number.length() == 11 && number.startsWith( "8"  ) )
        {
            return 7 + number.substring( 1 );
        }
        return number;
    }
}
