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

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
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.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;

public class HarrisMediator
    extends AbstractMediator
{
    @Override
    public Object init( Setup setup, int moduleId, VoiceDevice device, VoiceDeviceType deviceType, ParameterMap config )
        throws Exception
    {
        return super.init( setup, moduleId, device, deviceType, config );        
    }

    // пример CDR
    // 0                   1     2           3   4   5   6
    // 2023-08-01T00:49:22 63600 78001000898 756 002 033 0
    protected VoiceRecord processLine( final VoiceRecordProcessor processor, final String[] params )
        throws InterruptedException
    {
        CDR cdr = CDR.toCDR( params );
        if ( skipCDR( cdr ) )
        {
            return null;
        }
        
        final VoiceRecord record = processor.next();
        record.sessionStart = TimeUtils.convertLocalDateTimeToDate( cdr.start );
        record.duration = record.connectionDuration = cdr.amount;
        record.callingStationId = params[1].replaceAll( "[^0-9]*", "" );
        record.e164CallingStationId = callingStationIdToE164( record.callingStationId ); 
        record.calledStationId = params[2].replaceAll( "[^0-9]*", "" );
        record.e164CalledStationId = calledStationIdToE164( record.calledStationId );
        record.trunkIncoming = cdr.trunkIncoming;
        record.trunkOutgoing = cdr.trunkOutgoing;
        record.category = params.length > 6 ? Utils.parseInt( params[6] ) : 0;
        return record;
    }
    
    @Override
    protected boolean skipCDR( CDR cdr )
    {
        if ( cdr.amount < 2 )
        {
            return true;
        }
        if ( cdr.numberB.matches( "^\\d{,4}$" ) )
        {
            return true;
        }
        return super.skipCDR( cdr );
    }
    
    protected void preload()
    {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHH");
        
        String path = device.getLogPath();

        File rootDir = new File( path );
        if ( !rootDir.exists() )
        {
            return;
        }

        File inboxDir = new File( rootDir, "inbox" );
        inboxDir.mkdirs();

        File processedDir = new File( rootDir, "processed" );
        processedDir.mkdirs();
        
        File bgDir = new File( rootDir, CDR_BG_DIR );
        bgDir.mkdirs();
        
        for ( File file : inboxDir.listFiles() )
        {
            if ( file.isDirectory() )
            {
                continue;
            }

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

            // читаем файл и раскладываем записи по часовым файлам
            try
            {
                Map<String, List<String>> cdrs = new HashMap<>();
                for ( String line : Files.readAllLines( file.toPath() ) )
                {
                    // 0   1      2      3      4      5    6    7   8    9   10                 11
                    // 004 230801 215042 000000 215142 3600 ---- 016 ---- 033 89091132404------- 63600---------.
                    if ( !line.matches( "^\\d{3} \\d{6} \\d{6} \\d{6} .+" ) )
                    {
                        continue;
                    }
                    String[] cdrData = line.split( " " );
                    
                    int year = 2000 + Utils.parseInt( cdrData[1].substring( 0, 2 ) );
                    int month = Utils.parseInt( cdrData[1].substring( 2, 4 ) );
                    int day = Utils.parseInt( cdrData[1].substring( 4 ) );
                    LocalDate startDate = LocalDate.of( year, month, day );
                    
                    boolean useUp = !"000000".equals( cdrData[3] );
                    int startHour = Utils.parseInt( cdrData[ useUp ? 3 : 2 ].substring( 0, 2 ) );
                    int startMinute = Utils.parseInt( cdrData[ useUp ? 3 : 2 ].substring( 2, 4 ) );
                    int startSecond = Utils.parseInt( cdrData[ useUp ? 3 : 2 ].substring( 4 ) );
                    LocalTime startTime = LocalTime.of( startHour, startMinute, startSecond );
                    
                    int stopHour = Utils.parseInt( cdrData[4].substring( 0, 2 ) );
                    int stopMinute = Utils.parseInt( cdrData[4].substring( 2, 4 ) );
                    int stopSecond = Utils.parseInt( cdrData[4].substring( 4 ) );
                    LocalTime stopTime = LocalTime.of( stopHour, stopMinute, stopSecond );
                    LocalDateTime stop = LocalDateTime.of( startTime.isBefore( stopTime ) ? startDate : startDate.plusDays( 1 ), stopTime );
                    
                    CDR cdr = new CDR();
                    cdr.start = LocalDateTime.of( startDate, startTime );
                    cdr.numberA = cdrData[11].replace( "-", "" )
                        .replaceAll( "^9(\\d{9})$", "79$1" )
                        .replaceAll( "^89(\\d{9})$", "79$1" )
                        .replaceAll( "^8800(\\d{7})$", "7800$1" )
                        .replaceAll( "^8(\\d{10})$", "7$1" );
                    cdr.origNumberA = cdrData[11].replace( "-", "" );
                    cdr.numberB = cdrData[10].replace( "-", "" )
                        .replaceAll( "^8800(\\d{7})$", "7800$1" )
                        .replaceAll( "^8(\\d{10})$", "7$1" );
                    cdr.trunkIncoming = cdrData[7];
                    cdr.trunkOutgoing = cdrData[9];
                    cdr.amount = (int)ChronoUnit.SECONDS.between( cdr.start, stop );
                    
                    String date = cdr.start.format( formatter );
                    List<String> list = cdrs.get( date );
                    if ( list == null )
                    {
                        list = new ArrayList<>();
                        cdrs.put( date, list );
                    }
                    list.add( cdr.toString() );                    
                }
                
                for ( String key : cdrs.keySet() )
                {
                    Path dayPath = Paths.get( bgDir.toString(), key.substring( 0, 4 ), key.substring( 4, 6 ), key.substring( 6, 8 ) );
                    Files.createDirectories( dayPath );
                    Path cdrPath = Paths.get( dayPath.toString(), key.substring( 8 ) );
                    Set<String> cdrSet = new LinkedHashSet<>();
                    if ( Files.exists( cdrPath ) )
                    {
                        for ( String cdr : Files.readAllLines( cdrPath ) )
                        {
                            cdrSet.add( cdr );
                        }
                    }
                    cdrSet.addAll( cdrs.get( key ) );
                    //
                    StringBuffer buffer = new StringBuffer();
                    for ( String s : cdrSet )
                    {
                        buffer.append( s ).append( "\n" );
                    }
                    Files.writeString( cdrPath, buffer.toString(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE );
                }
                
                // перемещаем исходный файл в папку обработанные
                Files.move( file.toPath(), Paths.get( processedDir.getPath(), file.getName() ) );
            }
            catch( FileNotFoundException e )
            {
                logger.error( e );
            }
            catch( IOException e )
            {
                logger.error( e );
            }
        }
    }
}