
using System;
using System.Collections;
using System.Collections.Generic;

using System.IO;

namespace Rokojori
{  
  public class FilesSync
  {
    public static void Move( string fromPath, string toPath )
    {
      string? destinationDirectory = Path.GetDirectoryName( toPath );

      if ( ! string.IsNullOrEmpty( destinationDirectory ) && ! Directory.Exists( destinationDirectory ) )
      {
        Directory.CreateDirectory(destinationDirectory);
      }

      File.Move( fromPath, toPath );
    }

    public static void Delete( string path )
    {
      if ( string.IsNullOrWhiteSpace( path ) )
      {
        return;
      }

      if ( File.Exists( path ) )
      {
        File.Delete( path );

        return;
      }

      if ( ! Directory.Exists( path ) )
      {
        return;
      }

      Directory.Delete( path, recursive: true );        
      
    }

    public static bool DirectoryExists( string path )
    {
      return Directory.Exists( path );
    }

    public static bool FileExists( string path )
    {
      return File.Exists( path );
    }

    public static void CreateDirectory( string path )
    {
      Directory.CreateDirectory( path );
    }

    public static void EnsureParentDirectoryExists( string path )
    {
      EnsureDirectoryExists( RegexUtility.ParentPath( path ) );
    }

    public static void EnsureDirectoryExists( string path )
    {
      if ( DirectoryExists( path ) )
      {
        return;
      }

      CreateDirectory( path );
    }

    public static List<FilePath> GetDirectories( string path, System.Func<FilePath,bool> evaluator = null )
    {
      var list = new List<FilePath>(); 

      var files = Directory.GetDirectories( path, "*", SearchOption.TopDirectoryOnly );
      
      var absolutePath = FilePath.Absolute( path );

      for ( int i = 0; i < files.Length; i++ )
      {
        var fileName = Path.GetFileName( files[ i ] );

        var relativePath = absolutePath.MakeRelative( fileName );

        if ( evaluator == null || evaluator( relativePath ) )
        {
          list.Add( relativePath );
        }
      }

      return list;
    } 

    public static List<FilePath> GetFilesRecursive( string path, System.Func<FilePath,bool> evaluator = null )
    {
      return GetFiles( path, evaluator, true );
    }

    public static List<FilePath> GetFiles( string path, System.Func<FilePath,bool> evaluator = null, bool recursive = false )
    {
      if ( ! Directory.Exists( path ) )
      {
        return [];
      }

      var list = new List<FilePath>(); 

      var files = Directory.GetFiles( path, "*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly );
      

      var absoluteFilePath = FilePath.Absolute( path );

      for ( int i = 0; i < files.Length; i++ )
      {
        var relativePath = absoluteFilePath.MakeAbsolutePathRelative( files[ i ] );

        if ( evaluator == null || evaluator( relativePath ) )
        {
          list.Add( relativePath );
        }
      }

      return list;
    }

    public static bool SaveUTF8( string path, string data )
    {
      try
      {
        using ( StreamWriter streamWriter = File.CreateText( path ) )
        {
          streamWriter.Write( data );
        }
      }
      catch ( System.Exception e )
      {
        RJLog.Log( "Could not save text: ", path, "exception", e );
        return false;
      } 

      return true;

    }

    public static bool SaveJSON( string path, object obj )
    {
      return SaveUTF8( path, JSON.StringifyObject( obj ) );
    }     

    public static DateTimeOffset GetModificationTime( string path )
    {
      return File.GetLastWriteTimeUtc( path );
    }

    public static ISOTimeStamp GetModificationTimeStamp( string path )
    {
      return ISOTimeStamp.FromDate( GetModificationTime( path ) );
    }

    public static string LoadUTF8( string path )
    {
      try
      {
        using ( StreamReader streamReader = File.OpenText( path ) )
        {
          return streamReader.ReadToEnd();
        }
      }
      catch ( System.Exception e )
      {
        RJLog.Log( "Could not load text: ", path, "exception", e );
      }

      return null;
    }

    public static T LoadJSON<T>( string path ) where T:new()
    {
      if ( ! FilesSync.FileExists( path ) )
      {
        return default(T);
      }

      var jsonString = LoadUTF8( path );
      return JSON.ParseObject<T>( jsonString );
    }  

    public static bool SaveBytes( string fileName, byte[] byteArray )
    {
      try
      {
        using ( var fs = new FileStream( fileName, FileMode.Create, FileAccess.Write ) )
        {
          fs.Write( byteArray, 0, byteArray.Length );
          return true;
        }
      }
      catch ( System.Exception e )
      {
        RJLog.Log( "Exception caught in process: {0}", e );
        return false;
      }
      
    }
  }

  
  
}