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

import java.io.File;
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.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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;

import ru.bitel.bgbilling.modules.voice.server.runtime.VoiceSessionRuntime;

public class SmgM9Mediator
    extends AbstractMediator
{
    private static final String FILE_PREFIX = "";
    private static final String REGION_PREFIX = "7495";

    @Override
    public void readHourDataLog( VoiceRecordProcessor processor, Date hour )
        throws Exception
    {
        preload();

        LocalDateTime hourDateTime = TimeUtils.convertDateToLocalDateTime( hour );
        String hourDateTimeStr = hourDateTime != null ? DateTimeFormatter.ofPattern( "yyyy-MM-dd HH:mm" ).format( hourDateTime ) : "";
        String path = device.getLogPath();
        if ( getLogger().isDebugEnabled() )
        {
            getLogger().debug( "readHourDataLog():" );
            getLogger().debug( "\thour = " + hourDateTimeStr );
            getLogger().debug( "\tpath = " + path );
        }

        String logPath = path + "/" + FILE_PREFIX + TimeUtils.format( hour, "yyyyMMdd" ) + ".cdr";
        if ( getLogger().isDebugEnabled() )
        {
            getLogger().debug( "fullPath = " + logPath );
        }

        Path logFile = Paths.get( ( logPath ) );
        boolean exists = Files.exists( logFile );
        if ( getLogger().isDebugEnabled() )
        {
            getLogger().debug( "logFile exists => " + exists );
        }

        if ( !exists )
        {
            getLogger().warn( "log for " + hourDateTimeStr + " not exists" );
            return;
        }

        for( String line : Files.readAllLines( logFile ) )
        {
            String[] params = line.split( ";" );
            if ( params.length > 9  )
            //if (params.length == 8 && Integer.parseInt (params[6]) > 2)
            {
                processLine( processor, params );
            }
            else
            {
                getLogger().warn( "Skip line: " + line + "=>param.size"+params.length );
            }
        }
    }

//    устройство; дата время; длительность; вх транк; номер А; исх транк; далее служебная информация    
//    SmgM9;2024-12-10 09:36:40;0;148-HW;74952800222;047-sipMstT;74959801900;192.168.11.21;originate;20241130090056-10603;50;incomplete number;;
//    SmgM9;2024-12-10 12:08:11;3;148-HW;74952800222;047-sipMstT;74959801900;192.168.11.21;originate;20241130090056-10800;16;user answer;;
//    SmgM9;2024-12-10 12:16:55;14;148-HW;74952800222;047-sipMstT;74959801900;192.168.11.21;originate;20241130090056-10808;16;user answer;;
//    SmgM9;2024-12-10 12:46:10;3;148-HW;74952800222;047-sipMstT;74959801900;192.168.11.21;originate;20241130090056-10842;16;user answer;;
    protected VoiceRecord processLine( final VoiceRecordProcessor processor, final String[] params )
        throws InterruptedException
    {
        if ( Integer.parseInt (params[2]) < 3 )
        {
            return null;
        }
        String e164CallingStationId = params[4];
        String e164CalledStationId = params[6];

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

        final VoiceRecord record = processor.next();
        record.trunkIncoming = params[3];
        record.callingStationId = params[4];
        record.calledStationId = params[6];
        record.trunkOutgoing = params[5];
        record.e164CallingStationId = e164CallingStationId;
        record.e164CalledStationId = e164CalledStationId;
        String dateTime = params[1] ;
        record.sessionStart = TimeUtils.parseDate( dateTime, "yyy-MM-dd HH:mm:ss" );
        record.connectionDuration = Utils.parseInt( params[2], 0 );
        record.duration = Utils.parseInt( params[2], 0 );

        if ( getLogger().isDebugEnabled() )
        {
            getLogger().debug( "e164CallingStationId => " + e164CallingStationId + "; e164CalledStationId = " + e164CalledStationId + "; trunkIncoming = " + record.trunkIncoming );
        }
        
        return record;
    }

    @Override
    public void getLogExists( Date month, int[] data )
    {
        String path = device.getLogPath();

        if ( getLogger().isDebugEnabled() )
        {
            getLogger().debug( "getLogExists: month = " + month + "; path = " + path );
        }

        Path rootDirPath = Paths.get( path );
        if ( Files.notExists( rootDirPath ) )
        {
            if ( getLogger().isDebugEnabled() )
            {
                getLogger().debug( "rootDirPath = " + rootDirPath + " not exists" );
            }
            return;
        }

        LocalDate monthLocalDate = TimeUtils.convertDateToLocalDate( month );

        String mm = String.format( "%02d", monthLocalDate.getMonthValue() );
        String yy = String.format( "%04d", monthLocalDate.getYear() );

        if ( getLogger().isDebugEnabled() )
        {
            getLogger().debug( "monthLocalDate = " + monthLocalDate + "; mm = " + mm + "; yy = " + yy );
        }

        Path monthDirPath = Paths.get( rootDirPath.toString(), yy, mm );
        if ( Files.notExists( monthDirPath ) )
        {
            if ( getLogger().isDebugEnabled() )
            {
                getLogger().debug( "monthDirPath = " + monthDirPath + " not exists" );
            }
            return;
        }

        if ( getLogger().isDebugEnabled() )
        {
            getLogger().debug( "monthDirPath = {}", monthDirPath );
        }

        for ( File dayDir : monthDirPath.toFile().listFiles() )
        {
            if ( dayDir.isDirectory() )
            {
                final int day = Utils.parseInt( dayDir.getName().toString() );
                for ( File hourFile : dayDir.listFiles() )
                {
                    if ( hourFile.isFile() )
                    {
                        String fileName = hourFile.getName().toString();
                        data[ day - 1] |= (1 << Utils.parseInt( fileName.substring( 0, fileName.indexOf( '.' ) ) ));
                    }
                };
            }
        };
    }

    protected void preload()
    {
        String path = device.getLogPath();

        if ( getLogger().isDebugEnabled() )
        {
            getLogger().debug( "preload: path = " + path );
        }

        Path rootDirPath = Paths.get( path );
        if ( Files.notExists( rootDirPath ) )
        {
            if ( getLogger().isDebugEnabled() )
            {
                getLogger().debug( "rootDirPath = " + rootDirPath + " not exists" );
            }
            return;
        }

        for ( File listPath : rootDirPath.toFile().listFiles() )
        {
            //if ( listPath.isFile() && listPath.getName().matches( "cdr_log_\\d+_\\d+_\\d+\\.log" ) )
            if ( listPath.isFile() && listPath.getName().matches( "Day\\d+\\.cdr" ) )
            {
                try
                {
                    Pattern pattern = Pattern.compile( ".*(\\d{2}-\\d{2}-\\d{2} \\d{2}):.*" );
                    Map<String,List<String>> cdrs = new HashMap<>();
                    for ( String cdr : Files.readAllLines( Paths.get( listPath.toURI() ) ) )
                    {
                        Matcher matcher = pattern.matcher( cdr );
                        if ( matcher.matches() )
                        {
                            String key = matcher.group( 1 ).replace( '-', '_' ).replace( ' ', '_' );
                            List<String> list = cdrs.getOrDefault( key, new ArrayList<>() );
                            cdrs.put( key, list );
                            list.add( cdr );
                        }
                    }

                    for ( String key : cdrs.keySet() )
                    {
                        String[] dir = key.split( "_" );
                        Path logPath = Paths.get( rootDirPath.toString(), "20" + dir[2], dir[1], dir[0], dir[3] + ".log" );
                        if ( Files.notExists( logPath.getParent() ) )
                        {
                            Files.createDirectories( logPath.getParent() );
                        }
                        Files.write( logPath, cdrs.get( key ), StandardOpenOption.APPEND, StandardOpenOption.CREATE );
                    }

                    Path proccessPath = Paths.get( rootDirPath.toString(), "proccess" );
                    if ( Files.notExists( proccessPath ) )
                    {
                        Files.createDirectories( proccessPath );
                    }
                    Files.move( Paths.get( listPath.toURI() ), Paths.get( proccessPath.toString(), listPath.getName() ) );
                }
                catch( IOException ex )
                {
                    logError( ex );
                }
            }
        };
    }

    private String prepareNumber( String number )
    {
        if ( number.length() == 10 )
        {
            return 7 + number;
        }
        else if ( number.startsWith( "810" ) )
        {
            return number.substring( 3  );
        }
        else if ( number.startsWith( "8" ) )
        {
            return 7 + number.substring( 1 );
        }
        else if ( number.length() == 7 )
        {
            return REGION_PREFIX + number;
        }
        else if ( number.length() < 5 )
        {
            return 7000 + number;
        }
        return number;
    }

    public boolean postSessionCreate( List<VoiceSessionRuntime> recordSessions, VoiceRecord record, boolean abonError, boolean operError )
    {
        System.out.println(record.calledStationId+"=>"+abonError+"|"+operError);
        return abonError;
    }
}