using salesbook.Shared.Core.Dto;
using salesbook.Shared.Core.Interface;

namespace salesbook.Maui.Core.Services;

public class AttachedService : IAttachedService
{
    public async Task<AttachedDTO?> SelectImageFromCamera()
    {
        var cameraPerm = await Permissions.RequestAsync<Permissions.Camera>();
        if (cameraPerm != PermissionStatus.Granted)
            return null;

        FileResult? result = null;

        try
        {
            result = await MediaPicker.Default.CapturePhotoAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Errore cattura foto: {ex.Message}");
            return null;
        }

        return result is null ? null : await ConvertToDto(result, AttachedDTO.TypeAttached.Image);
    }

    public async Task<AttachedDTO?> SelectImageFromGallery()
    {
        var storagePerm = await Permissions.RequestAsync<Permissions.StorageRead>();
        if (storagePerm != PermissionStatus.Granted)
            return null;

        FileResult? result = null;

        try
        {
            result = await MediaPicker.Default.PickPhotoAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Errore selezione galleria: {ex.Message}");
            return null;
        }

        return result is null ? null : await ConvertToDto(result, AttachedDTO.TypeAttached.Image);
    }


    public async Task<AttachedDTO?> SelectFile()
    {
        var perm = await Permissions.RequestAsync<Permissions.StorageRead>();
        if (perm != PermissionStatus.Granted) return null;

        var result = await FilePicker.PickAsync();

        return result is null ? null : await ConvertToDto(result, AttachedDTO.TypeAttached.Document);
    }

    public async Task<AttachedDTO?> SelectPosition()
    {
        var perm = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
        if (perm != PermissionStatus.Granted) return null;

        var loc = await Geolocation.GetLastKnownLocationAsync();
        if (loc is null) return null;

        return new AttachedDTO
        {
            Name = "Posizione attuale",
            Lat = loc.Latitude,
            Lng = loc.Longitude,
            Type = AttachedDTO.TypeAttached.Position
        };
    }

    private static async Task<AttachedDTO> ConvertToDto(FileResult file, AttachedDTO.TypeAttached type)
    {
        var stream = await file.OpenReadAsync();
        using var ms = new MemoryStream();
        await stream.CopyToAsync(ms);

        return new AttachedDTO
        {
            Name = file.FileName,
            Path = file.FullPath,
            MimeType = file.ContentType,
            DimensionBytes = ms.Length,
            FileBytes = ms.ToArray(),
            Type = type
        };
    }

    private static async Task<string?> SaveToTempStorage(Stream file, string fileName)
    {
        var cacheDirectory = FileSystem.CacheDirectory;
        var targetDirectory = Path.Combine(cacheDirectory, "file");

        if (!Directory.Exists(targetDirectory)) Directory.CreateDirectory(targetDirectory);

        var tempFilePath = Path.Combine(targetDirectory, fileName + ".temp");
        var filePath = Path.Combine(targetDirectory, fileName);

        if (File.Exists(filePath)) return filePath;

        try
        {
            await using var fileStream =
                new FileStream(tempFilePath, FileMode.Create, FileAccess.Write, FileShare.None);
            await file.CopyToAsync(fileStream);

            File.Move(tempFilePath, filePath);
        }
        catch (Exception e)
        {
            Console.WriteLine($"Errore durante il salvataggio dello stream: {e.Message}");
            return null;
        }
        finally
        {
            if (File.Exists(tempFilePath)) File.Delete(tempFilePath);
        }

        return filePath;
    }

    public async Task OpenFile(Stream file, string fileName)
    {
        var filePath = await SaveToTempStorage(file, fileName);
        
        if (filePath is null) return;
        await Launcher.OpenAsync(new OpenFileRequest
        {
            File = new ReadOnlyFile(filePath)
        });
    }
}