import hashlib
from PIL import Image
from app.routes.asset import CreateFakeAsset
from app.routes.thumbnailer import ValidatePlaceFileRequest
from app.enums.PlaceYear import PlaceYear
from app.util import s3helper
import uuid
import time
import json
import os
import logging
import eyed3
import tempfile
import ffmpeg

# TODO: Make this less shit

def ValidateClothingImage( file, verifyResolution = True, validateFileSize = True, returnImage = False ):
    try:
        file.seek(0, os.SEEK_END)
        FileSize = file.tell()
        if FileSize > 1024 * 1024 and validateFileSize:
            raise Exception("File is larger than 1MB")

        ImageObj = Image.open(file)
        ImageObj.verify()
        
        if ImageObj.format != "PNG":
            raise Exception("File is not a PNG file")
        
        if ImageObj.size != (585, 559) and verifyResolution:
            raise Exception("File is not 585 x 559")
        
        if returnImage:
            file.seek(0, os.SEEK_END)

            ImageObj = Image.open(file).convert("RGBA")
            ImageData = list(ImageObj.getdata())
            SanitizedImage = Image.new(ImageObj.mode, ImageObj.size)
            SanitizedImage.putdata(ImageData)

            return SanitizedImage
        
    except Exception as e:
        return False
    return True

def ValidatePlaceFile( file, keepFileWhenInvalid = False, TestPlaceYear : PlaceYear = PlaceYear.Eighteen, bypassCache : bool = False ):
    try:
        from app.extensions import redis_controller
        file.seek(0, os.SEEK_END)
        FileSize = file.tell()
        if FileSize > 1024 * 1024 * 30:
            raise Exception("File is larger than 30MB")
        file.seek(0)
        FileContents = file.read()
        FileHash = hashlib.sha512(FileContents).hexdigest()

        if not bypassCache:
            validationResults : int | None = redis_controller.get(f"ValidatePlaceFile:{FileHash}:{TestPlaceYear.value}")
            if validationResults is not None:
                return validationResults == 1

        s3helper.UploadBytesToS3(FileContents, FileHash)
        TemporaryAssetId = CreateFakeAsset(AssetName = "AssetValidationService", Expiration = 60 * 10, AssetFileHash = FileHash)
        PlaceValidationReqUUID = str(uuid.uuid4())
        
        ValidatePlaceFileRequest( TemporaryAssetId, PlaceValidationReqUUID, TestPlaceYear)
        logging.info(f"Sent validation request for '{FileHash}' with UUID {PlaceValidationReqUUID}")
        StartTime = time.time()
        ResponseInfo = None
        while True:
            if time.time() - StartTime > 45:
                raise Exception("Timed out while waiting for a response from AssetValidation Service")
            ResponseInfo = redis_controller.get(f"ValidatePlaceFileRequest:{PlaceValidationReqUUID}")
            if ResponseInfo is None:
                time.sleep(0.2)
                continue
            else:
                break
        if ResponseInfo is not None:
            ResponseInfo = json.loads(ResponseInfo)
            if ResponseInfo["valid"]:
                redis_controller.set(f"ValidatePlaceFile:{FileHash}:{TestPlaceYear.value}", 1, 60 * 60 * 24 * 2)
                return True
            else:
                redis_controller.set(f"ValidatePlaceFile:{FileHash}:{TestPlaceYear.value}", 0, 60 * 60 * 24 * 2)
                raise Exception(ResponseInfo["error"])
    except Exception as e:
        if not keepFileWhenInvalid:
            try:
                s3helper.DeleteFileFromR2(FileHash)
            except:
                pass
        return str(e)
    return True

def ValidateMP3File( file ) -> int | None:
    """
        Validates an MP3 file and returns duration in seconds
    """
    TemporaryFile = tempfile.NamedTemporaryFile(suffix=".mp3", delete=True)
    file.seek(0)
    TemporaryFile.write(file.read())
    try:
        AudioFile = eyed3.load(TemporaryFile.name)
        if AudioFile is None:
            return None
        TemporaryFile.close()
        return AudioFile.info.time_secs
    except Exception as e:
        logging.error(f"Failed to validate MP3 file: {e}")
        return None

def ValidateMP3AndConvertToOGG( file ) -> (bytes, int):
    """
        Validates given file is a MP3 File and then converts it into the OGG format and returns the bytes and length of the sound in seconds
    """
    TemporaryFile = tempfile.NamedTemporaryFile(suffix=".mp3", delete=True)
    OutputTemporaryFile = tempfile.NamedTemporaryFile(suffix=".ogg", delete=True)
    try:
        file.seek(0)
        TemporaryFile.write(file.read())

        AudioFile = eyed3.load(TemporaryFile.name)
        if AudioFile is None:
            TemporaryFile.close()
            raise Exception("Failed to load MP3 file")
        FFmpegStream = ffmpeg.input(TemporaryFile.name, vn=None)
        FFmpegStream = ffmpeg.output(FFmpegStream, OutputTemporaryFile.name, acodec="libvorbis", f="ogg")
        ffmpeg.run(FFmpegStream, overwrite_output = True, quiet = True, capture_stdout = False, capture_stderr = False)
        OutputTemporaryFile.seek(0)
        OutputFileBytes = OutputTemporaryFile.read()

        ProbeResult = ffmpeg.probe(OutputTemporaryFile.name, select_streams="a")
        AudioDuration = float(ProbeResult["streams"][0]["duration"])

        OutputTemporaryFile.close()
        TemporaryFile.close()
        return OutputFileBytes, AudioDuration
    except Exception as e:
        logging.error(f"Failed to validate MP3 file: {e}")

        TemporaryFile.close()
        OutputTemporaryFile.close()
        raise e