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

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

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.common.TimeUtils;
import ru.bitel.common.Utils;

public class S12Mediator
	extends AbstractMediator
{
	private DateFormat sessionDateFormat = new SimpleDateFormat( "yyyyMMdd HHmmss" );
	
	@Override
	public void readHourDataLog( final VoiceRecordProcessor processor, final Date hour )
		throws Exception
	{    			    
        LocalDateTime time = TimeUtils.convertDateToLocalDateTime( hour );
        
        // предобработка логов
        // берем все новые файлы логов и делим по часам + копии перемещаем в папки по часам
        // исходный файл перемещаем в папку обработаные
        preload();
        
        readHourDataLog( processor, time );
	}
	
	private void readHourDataLog( final VoiceRecordProcessor processor, final LocalDateTime hour )
	{
	    // путь к папке с логами
        String path = device.getLogPath();
        
        if ( getLogger().isDebugEnabled() )
        {
            getLogger().debug( "path = " + path );
        }

        File rootDir = new File( path );
        if ( !rootDir.exists() )
        {
            return;
        }
        
        // день + час за который надо обработать логи
        String prefix = hour.format( DateTimeFormatter.ofPattern( "yyyyMMddHH" ) );
        
        File s12bgDir = new File( rootDir.getParentFile(), "s12_bg" );
        s12bgDir.mkdirs();

        File file = new File( s12bgDir, prefix.substring( 0, 4 ) + File.separator + prefix.substring( 4, 6 ) + File.separator + prefix.substring( 6, 8 ) + File.separator + prefix.substring( 8 ) );
        if ( file.exists() )
        {
            if ( getLogger().isDebugEnabled() )
            {
                getLogger().debug( "file = " + file );
            }
            try (BufferedReader reader = new BufferedReader( new InputStreamReader( new FileInputStream( file ) ), 128 * 1024 ))
            {
                String line;
                while( (line = reader.readLine()) != null )
                {
                    // для каждой строки проверяем дату и время
                    if ( line.length() == 105 )
                    {
                        processLine( processor, line.split( " " ) );
                    }
                }
            }
            catch( IOException ex )
            {
                logError( ex );
            }
            catch( InterruptedException ex )
            {
                logError( ex );
            }
        }
	}
	
	@Override
	public void getLogExists( Date month, int[] data )
	{
	    String path = device.getLogPath();
	    
        File rootDir = new File( path );
        if ( !rootDir.exists() )
        {
            return;
        }

        long start = System.currentTimeMillis();
        
        File s12bgDir = new File( rootDir.getParentFile(), "s12_bg" );
        s12bgDir.mkdirs();

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern( "yyyyMMddHH" );

        LocalDateTime hour = TimeUtils.convertDateToLocalDateTime( month );
        hour = hour.truncatedTo( ChronoUnit.DAYS ).withDayOfMonth( 1 );
        LocalDateTime nextMonth = hour.plusMonths( 1 );
        while ( hour.isBefore( nextMonth ) )
        {
            String prefix = hour.format( dateTimeFormatter );
            File file = new File( s12bgDir, prefix.substring( 0, 4 ) + File.separator + prefix.substring( 4, 6 ) + File.separator + prefix.substring( 6, 8 ) + File.separator + prefix.substring( 8 ) );
            if ( file.exists() )
            {
                data[hour.getDayOfMonth() - 1] |= ( 1 << hour.getHour() );
            }
            hour = hour.plusHours( 1 );
        }
        if ( getLogger().isDebugEnabled() )
        {
            for ( int day = 0; day < data.length; day++ )
            {
                StringBuffer str = new StringBuffer();
                for ( int h = 0; h < 24; h++ )
                {
                    str.append( (data[day] & (1 << h)) > 0 ? "1" : "0" );
                }
                getLogger().debug( String.format( "day => %2d   hour => %24s", ( day + 1 ), str.toString() ) );
            }
        }
        getLogger().info( "getLogExists run time = " + ( System.currentTimeMillis() - start ) + "ms" );
	}

	// пример CDR
	// 20191224 071559 8313091809FFFFFF 62230FFFFFFFFFFFFFFFFFFFFFFFFF 000404 0 245 000006 00 00 0 0 0000 0001 3
	protected VoiceRecord processLine( final VoiceRecordProcessor processor, final String[] params )
		throws InterruptedException
	{
		VoiceRecord record = processor.next();
		record.sessionStart = TimeUtils.parseDate( params[0] + " " + params[1], sessionDateFormat );
		record.duration = record.connectionDuration = Utils.parseInt( params[4].substring( 0, 2 ), 0 ) * 3600 + Utils.parseInt( params[4].substring( 2, 2 ), 0 ) * 60 + Utils.parseInt( params[4].substring( 4 ), 0 );
		record.callingStationId = params[2].replaceAll( "[^0-9]*", "" );
		record.e164CallingStationId = callingStationIdToE164( record.callingStationId ); 
		record.calledStationId = params[3].replaceAll( "[^0-9]*", "" );
		record.e164CalledStationId = calledStationIdToE164( record.calledStationId );
		record.trunkIncoming = params[12];
		record.trunkOutgoing = params[13];
		record.category = Utils.parseInt( params[6], 0 );
		return record;
	}
	
	protected void preload()
	{
        String path = device.getLogPath();

        File rootDir = new File( path );
        if ( !rootDir.exists() )
        {
            return;
        }
        
        File s12bgDir = new File( rootDir.getParentFile(), "s12_bg" );
        s12bgDir.mkdirs();
        
        File processedDir = new File( s12bgDir, "processed" );
        processedDir.mkdirs();
        
        for ( File file : rootDir.listFiles() )
        {
            if ( file.isDirectory() )
            {
                continue;
            }

            if ( file.getName().startsWith( "." ) )
            {
                continue;
            }
            
            if ( new File( processedDir, file.getName() ).exists() )
            {
                continue;
            }

            Map<String, StringBuffer> cdrs = new HashMap<>();
            // читаем файл и раскладываем записи по часовым файлам
            try (BufferedReader reader = new BufferedReader( new InputStreamReader( new FileInputStream( file ) ), 128 * 1024 ))
            {
                String line;
                while( (line = reader.readLine()) != null )
                {
                    String date = line.substring( 0, 11 ).replaceAll( " ", "" );
                    StringBuffer buffer = cdrs.get( date );
                    if ( buffer == null )
                    {
                        buffer = new StringBuffer();
                        cdrs.put( date, buffer );
                    }
                    buffer.append( line ).append( "\n" );
                }
                
                for ( String key : cdrs.keySet() )
                {
                    File dayDir = new File( s12bgDir, key.substring( 0, 4 ) + File.separator + key.substring( 4, 6 ) + File.separator + key.substring( 6, 8 ) );
                    dayDir.mkdirs();
                    
                    File hourFile = new File( dayDir, key.substring( 8 ) );
                    BufferedWriter bufferWriter = new BufferedWriter( new FileWriter( hourFile, true ) );
                    bufferWriter.write( cdrs.get( key ).toString() );
                    bufferWriter.close();
                }
                
                // перемещаем исходный файл в папку обработанные
                new File( processedDir, file.getName() ).createNewFile();
            }
            catch( IOException ex )
            {
                logError( ex );
            }
        }
	}
	
    class CDRFileFilter
        implements FilenameFilter
    {
        private boolean add = false;
        private String prefix = "";
        
        public CDRFileFilter( final String prefix, final boolean add )
        {
            this.prefix = prefix;
            this.add = add;
        }
        
        @Override
        public boolean accept( File dir, String name )
        {
            return ( ( name.startsWith( prefix ) && name.endsWith( ".srm" ) ) || ( add && name.startsWith( prefix.substring( 0, 6 ) ) && name.endsWith( ".add" ) ) );
        }
    }
}
