##################################
######     CONSTANTS     #########
##################################

$global:FileTypePropIndex = 11
$global:ImageCreationDatePropIndex = 12
$global:VideoCreationDatePropIndex = 208

##################################
######     FUNCTIONS     #########
##################################

function Get-APImageVideoExtensions {
    param (
        [string] $sourceUrl = "https://cdn.jsdelivr.net/gh/jshttp/mime-db@v1.52.0/db.json"
    )
    $jsonData = (Invoke-RestMethod $sourceUrl).PSObject.Properties
    $extensions = @()

    foreach ($item in $jsonData) {
        if ($item.Name -match "^(image|video)") {
            $extensions += $item.Value.extensions
        }
    }

    $extensions = $extensions | Sort-Object -Unique
    return $extensions
}

function Get-APFileMetaData {
    param (
        [string] $filePath,
        [int] $propertyIndex
    )

    $folder = (New-Object -ComObject Shell.Application).NameSpace((Split-Path -Parent $filePath))
    $folderItem = $folder.ParseName((Split-Path -Leaf $filePath))

    $property = $folder.GetDetailsOf(
        $folderItem,
        $propertyIndex
    )

    return $property
}

function Get-APTemporaryDirectory {
    do {
        $tempDir = Join-Path -Path $env:TEMP -ChildPath ([System.IO.Path]::GetRandomFileName())
    } while (Test-Path $tempDir)
    return $tempDir
}

function Get-APDateFromJson {
    param (
        [string] $filePath
    )

    $jsonFilePath = $filePath + ".json"
    if (-not (Test-Path $jsonFilePath)) {
        return $null
    }

    $jsonContent = Get-Content -Path $jsonFilePath -Raw | ConvertFrom-Json
    $timestamp = [int64] $jsonContent.photoTakenTime.timestamp
    return [System.DateTimeOffset]::FromUnixTimeSeconds($timestamp).DateTime
}

function Get-APFileCreationDate {
    param (
        [string] $filePath,
        [string] $fileType
    )
    if ($fileType -ieq "vidéo") { $propIndex = $VideoCreationDatePropIndex }
    if ($fileType -ieq "image") { $propIndex = $ImageCreationDatePropIndex }
    $charWhiteList = '[^: \w\/]'

    $dateTaken = (Get-APFileMetaData -FilePath $filePath -PropertyIndex $propIndex) -replace $charWhiteList

    $culture = Get-Culture
    $dateTaken = try { [DateTime]::Parse($dateTaken, $culture) } catch { $null }
    return $dateTaken
}

function _subDirectoryFromDate {
    param (
        [string] $filePath,
        [Nullable[datetime]] $originalDate
    )

    if ($originalDate) {
        $year = $originalDate.Year
        $month = $originalDate.Month.ToString("D2")
        $monthName = Get-Culture | ForEach-Object { $_.DateTimeFormat.GetMonthName($month) }

        return "$year\$month - $monthName"
    } else {
        return "Non daté"
    }
}

###########################################
####              MAIN                #####
###########################################

if ($args[0] -and $args[1]) {
    $sourceDir = $args[0]
    $destinationDir = $args[1]
} else {
    $sourceDir = Read-Host "Veuillez entrer le chemin du dossier source (ou une archive .zip)"
    $destinationDir = Read-Host "Veuillez entrer le chemin du dossier destination"
}

if ($sourceDir -imatch "\.zip$") {
    $tempDir = Get-APTemporaryDirectory

    try {
        Expand-Archive -LiteralPath $sourceDir -DestinationPath $tempDir
        $sourceDir = $tempDir
    }catch{
        Write-Host "L'archive n'a pas pu être décompressée."
        return
    }
}

Get-ChildItem -Path $sourceDir -Recurse -File | ForEach-Object {
    $filePath = $_.FullName
    $fileType = (Get-APFileMetaData -File $filePath -PropertyIndex $FileTypePropIndex)

    if (-not($fileType -match "vidéo|image")) {
        Write-Host "Fichier ignoré: $($filePath)"
        return
    }

    $creationDate = if ($value = Get-APDateFromJson -filePath $filePath) {
        $value
    } else {
        Get-APFileCreationDate -filePath $filePath -fileType $fileType
    }
    $subFolder = _subDirectoryFromDate -filePath $filePath -originalDate $creationDate
    $targetDir = Join-Path -Path $DestinationDir -ChildPath $subFolder

    if (-not (Test-Path $targetDir)) {
        New-Item -Path $targetDir -ItemType Directory | Out-Null
    }

    Copy-Item -Path $filePath -Destination $targetDir
}

if ($sourceDir -like "$env:TEMP\*") {
    Remove-Item -Path $sourceDir -Recurse -Force
}