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

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

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 Smg1016mMediator
	extends AbstractMediator
{
    private static final String SMG1016M_BG = "smg1016m_bg";

	private DateFormat sessionDateFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
	
	private Map<String, Set<String>> processedCache = new HashMap<>();
	
	@Override
	public void readHourDataLog( final VoiceRecordProcessor processor, final Date hour )
		throws Exception
	{    			    
        LocalDateTime time = TimeUtils.convertDateToLocalDateTime( hour );
        
        // предобработка логов
        // берем все файлы папки с логами и сравниванием по названию с файлами которые ранее обработали, 
        // из тех файлов которые еще не обрабатывали записи ДОПИСЫВАЕМ в часовые логи
        // для исходный файла создаем пустой файл с таким же названием в папке pprocessed
        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 smg1016mbgDir = new File( rootDir.getParentFile(), SMG1016M_BG );
        smg1016mbgDir.mkdirs();

        File file = new File( smg1016mbgDir, 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 )
                {
                    processLine( processor, line.split( ";" ) );
                }
            }
            catch( IOException ex )
            {
                logError( ex );
            }
            catch( InterruptedException ex )
            {
                logError( ex );
            }
        }
	}

	// пример CDR (одна запись)
	// ;2019-12-14 09:54:30;35;16;user answer;192.168.77.210;trunk-SIP;KB50-TKG;95588;8313095588;0.0.0.0;trunk-SS7;ATS9 - SMG;61586;61586;
	// 2019-12-14 09:54:28;2019-12-14 09:55:05;normal;;;7;29;;93;90e445a0-f82a-4a0d-8eb8-cf4d1c6398c6;;10;228;3;3;;;
	// 11000045 5df48724 f6b5d3df 39c06001;answer;normal;;0;20191129011509-275537;
	protected VoiceRecord processLine( final VoiceRecordProcessor processor, final String[] params )
		throws InterruptedException
	{
	    int duration = Utils.parseInt( params[2], 0 );
        if ( duration == 0 )
        {
            return null;
        }
	    
		VoiceRecord record = processor.next();
		record.sessionStart = TimeUtils.parseDate( params[1], sessionDateFormat );
		record.duration = record.connectionDuration = duration;
		record.callingStationId = params[9].replaceAll( "[^0-9]*", "" );
		record.e164CallingStationId = callingStationIdToE164( record.callingStationId ); 
		record.calledStationId = params[14].replaceAll( "[^0-9]*", "" );
		record.e164CalledStationId = calledStationIdToE164( record.calledStationId );
		record.trunkIncoming = params[6];
		record.trunkOutgoing = params[11];
		record.category = 0;
		
		return record;
	}
	
	protected void preload()
	{
        String path = device.getLogPath();

        File rootDir = new File( path );
        if ( !rootDir.exists() )
        {
            return;
        }
        
        File smg1016mbgDir = new File( rootDir.getParentFile(), SMG1016M_BG );
        smg1016mbgDir.mkdirs();
        
        File processedDir = new File( smg1016mbgDir, "processed" );
        processedDir.mkdirs();
        
        for ( File file : rootDir.listFiles() )
        {
            if ( file.isDirectory() || !file.getName().endsWith( ".cdr" ) )
            {
                continue;
            }

            String yyymm = file.getName().substring( 0, 6 );
            Set<String> processedSet = processedCache.get( yyymm );
            File processedFile = new File( processedDir, yyymm );
            if ( processedSet == null )
            {
                processedSet = new HashSet<>();
                try
                {
                    if ( processedFile.exists() )
                    {
                        String line = null;
                        BufferedReader bufferedReader = Files.newBufferedReader( Paths.get( processedFile.getAbsolutePath() ) ); 
                        while ( ( line = bufferedReader.readLine() ) != null )
                        {
                            processedSet.add( line );
                        }
                        bufferedReader.close();
                    }
                    else
                    {
                        Files.createFile( Paths.get( processedFile.getAbsolutePath() ) );
                    }
                }
                catch( IOException ex )
                {
                    logError( ex );
                }
                processedCache.put( yyymm, processedSet );
            }
            if ( processedSet.contains( file.getName() )  )
            {
                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 )
                {
                    int pos1 = line.indexOf( ';' );
                    int pos2 = line.indexOf( ';', pos1 + 1 );
                    String date = line.substring( pos1 + 1, pos2 ).replaceAll( " ", "" ).replaceAll( "-", "" ).replaceAll( ":", "" ).substring( 0, 10 );
                    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( smg1016mbgDir, 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();
                }
                
                // добавляем в файлик YYYMM имя обработанного файла, как признак того, что файл обработан
                processedSet.add( file.getName() );
                BufferedWriter bufferedWriter = Files.newBufferedWriter( Paths.get( processedFile.getAbsolutePath() ), StandardCharsets.UTF_8, StandardOpenOption.APPEND );
                bufferedWriter.write( file.getName() );
                bufferedWriter.newLine();
                bufferedWriter.close();
            }
            catch( FileNotFoundException ex )
            {
                logError( ex );
            }
            catch( IOException ex )
            {
                logError( ex );
            }
        }
	}
}