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

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
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 AsteriskMediator_v3
    extends AbstractMediator
{
    @Override
    protected VoiceRecord processLine( VoiceRecordProcessor processor, String[] params )
        throws InterruptedException
    {
        CDR cdr = new CDR();
        cdr.amount = Utils.parseInt( params[3], 0 );
        if ( skipCDR( cdr ) )
        {
            return null;
        }
        
        // 0                       1               2       3       4       5      
        // 2024-01-01T00:01:45     32938810        8928    0       C335401 C000000

        VoiceRecord record = processor.next();
        record.sessionStart = TimeUtils.convertLocalDateTimeToDate( LocalDateTime.parse( params[0] ) );        
        record.callingStationId = params[1];
        record.e164CallingStationId = callingStationIdToE164( record.callingStationId );
        record.calledStationId = params[2];
        record.e164CalledStationId = calledStationIdToE164( record.calledStationId );
        record.duration = record.connectionDuration = Utils.parseInt( params[3], 0 );
        record.trunkIncoming = params[4];
        record.trunkOutgoing = params[5];
        record.category = 0;
        
        return record;
    }

    @Override
    protected void parseLog( Path path, Map<String, List<String>> cdrs )
    {
        if ( Files.exists( path ) )
        {
            try 
            {
                LocalDateTime now = LocalDateTime.now();
                int defYear = now.getYear() - 2000;
                int defMonth = now.getMonthValue();
                int defDayOfMonth = now.getDayOfMonth();
                int defHour = now.getHour();
                int defMinute = now.getMinute();
                int defSecond = now.getSecond();
                
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHH");
                
                Files.lines( path ).forEach( line ->
                {
                    logger.debug( "line = {}", line );

                    // "","9157391874","300#4452802","si",""""" <9157391874>","SIP/MEGAFON-0000f49f","SIP/si2000-0000f4a0","Dial","SIP/si2000/4452802,60","2024-06-09 00:49:23","2024-06-09 00:49:32","2024-06-09 00:50:30",67,58,"ANSWERED","DOCUMENTATION","1717883363.101826",""
                    // Поля
                    //
                    // 0 accountcode: Какой учетный номер используется: account, (строка, 20 символов)
                    // 1 src: Номер Caller*ID (строка, 80 символов)
                    // 2 dst: Расширение направления (строка, 80 символов)
                    // 3 dcontext: Контекст направления (строка, 80 символов)
                    // 4 clid: Caller*ID с текстом (80 символов)
                    // 5 channel: Используемый канал (80 символов)
                    // 6 dstchannel: Канал направления, если подходит (80 символов)
                    // 7 lastapp: Последнее приложение, если подходит (80 символов)
                    // 8 lastdata: Дата последнего приложения (аргументы) (80 символов)
                    // 9 start: Начало вызова (дата/время)
                    // 10 answer: Ответ вызова (дата/время)
                    // 11 end: Конец вызова (дата/время)
                    // 12 duration: Полное время в системе, в секундах (целое), от набора номера до зависания
                    // 13 billsec: Полное время вызова, в секундах (целое), от ответа до зависания
                    // 14 disposition: Что случилось с вызовом: ANSWERED, NO ANSWER, BUSY, FAILED (на некоторых CDR выходных буферах, например ODBC, они могут быть целыми; заметьте, что более детальная инфа может быть найдена в переменной диалплана $HANGUPCAUSE)
                    // 15 amaflags: Какой флаг используется: смотри amaflags: DOCUMENTATION, BILLING, IGNORE и т.д., указанного на базисе каждого канала подобно accountcode.                     
                    
                    List<String> params = parseLine( line );

                    CDR cdr = new CDR();

                    if ( params.size() < 11 )
                    {
                        return;
                    }

                    String ansCode =  params.get( 14 );
                    // отбрасывать можно звонки с кодом ответа
                    if ( ansCode.equals( "NO ANSWER" ) || ansCode.equals( "CONGESTION" ) )
                    {
                        return;
                    }
//                    System.out.println( "ansCode = " + params.get( 14 ) );
                    
                    // "2024-06-09 00:49:32"
                    System.out.println( params.get( 10 ) );
                    int year = Utils.parseInt( params.get( 10 ).substring( 0, 4 ), defYear );
                    int month = Utils.parseInt( params.get( 10 ).substring( 5, 7 ), defMonth );
                    int dayOfMonth = Utils.parseInt( params.get( 10 ).substring( 8, 10 ), defDayOfMonth );
                    int hour = Utils.parseInt( params.get( 10 ).substring( 11, 13 ), defHour );
                    int minute = Utils.parseInt( params.get( 10 ).substring( 13, 15 ), defMinute );
                    int second = Utils.parseInt( params.get( 10 ).substring( 16 ), defSecond );
                    cdr.start = LocalDateTime.of( year, month, dayOfMonth, hour, minute, second );
                    
                    cdr.numberA = params.get( 1 );
                    cdr.origNumberA = params.get( 1 );

                    cdr.numberB = params.get( 2 );
                    
                    cdr.trunkIncoming = params.get( 5 );
                    cdr.trunkOutgoing = params.get( 6 );

                    cdr.amount = Utils.parseInt( params.get( 13 ), 0 );
                    
                    String date = cdr.start.format( formatter );
                    List<String> buffer = cdrs.get( date );
                    if ( buffer == null )
                    {
                        buffer = new ArrayList<>();
                        cdrs.put( date, buffer );
                    }
                    buffer.add( cdr.toString() );
                    if ( logger.isDebugEnabled() )
                    {
                        logger.debug( "cdr => {}", cdr.toString() );
                    }
//                    
//                    System.out.println( cdr.toString() );
                } );
            }
            catch ( Exception ex )
            {
                logger.error( ex );
            }
        }
    }    
    
    public static void main( String[] args )
    {
        Path rootPath = Paths.get( args[0] );
        Path inboundPath = Paths.get( rootPath.toString(), "inbound" );

        if ( !Files.exists( inboundPath ) || !Files.isDirectory( inboundPath ) )
        {
            System.out.println( inboundPath.toString() + " каталог не найден" );
            System.exit( 1 );
        }
        
        try
        {
            Map<String, List<String>> cdrs = new HashMap<>();
            AsteriskMediator_v3 asteriskMediator_v3 = new AsteriskMediator_v3();
            Files.list( inboundPath ).forEach( f -> asteriskMediator_v3.parseLog( f, cdrs ) );
        }
        catch( Exception ex )
        {
            System.err.println( ex );
            System.exit( 2 );
        }
    }
}
