import bpy
import os
from ..util import *
from .dat_dtt_ui_manager import ShowMessageBox
import math

def to_int(bs):
    return (int.from_bytes(bs, byteorder='little'))

def to_string(bs, encoding = 'utf8'):
    return bs.split(b'\x00')[0].decode(encoding)

def main(dat_dir, export_filepath):
    files = []
    hash_file_path = None

    # Get hash_file_path
    for filepath in os.listdir(dat_dir):
        if 'hash_data.metadata' in filepath:
            hash_file_path = dat_dir + '\\' + filepath

    if hash_file_path == None:
        print('[!] DAT/DTT Error: hash_data.metadata not found.')
        ShowMessageBox('hash_data.metadata not found.', 'DAT/DTT Export Error', 'ERROR') 
        return

    # Get files and their order
    if os.path.isfile(dat_dir + '\\' + 'file_order.metadata'):
        file_orderFile = open(dat_dir + '\\' + 'file_order.metadata', 'rb')
        fileCount = to_int(file_orderFile.read(4))
        fileNameSize = to_int(file_orderFile.read(4))

        for i in range(fileCount):
            fileName = to_string(file_orderFile.read(fileNameSize))
            files.append(dat_dir + '\\' + fileName)
            print('[' + fileName + ']')
    else:
        print('[!] DAT/DTT Error: file_order.metadata not found.')
        ShowMessageBox('file_order.metadata not found.', 'DAT/DTT Export Error', 'ERROR') 
        return
    

    fileNumber = len(files)

    fileExtensionsSize = 0
    fileExtensions = []
    for fp in files:
        fileExt = fp.split('.')[-1]
        fileExtensionsSize += len(fileExt)+1
        fileExtensions.append(fileExt)

    nameLength = 0                              
    for fp in files:
        fileName = os.path.basename(fp)
        if len(fileName)+1 > nameLength:
            nameLength = len(fileName)+1

    fileNames = []                             
    for fp in files:
        fileName = os.path.basename(fp)
        fileNames.append(fileName)

    hashMapSize = os.path.getsize(hash_file_path)

    # Header
    fileID = 'DAT'
    fileNumber = fileNumber
    fileOffsetsOffset = 32
    fileExtensionsOffset = math.ceil((fileOffsetsOffset + (fileNumber * 4))/4)*4
    fileNamesOffset = math.ceil((fileExtensionsOffset + fileExtensionsSize)/4)*4
    fileSizesOffset = math.ceil((fileNamesOffset + (fileNumber * nameLength) + 4)/4)*4
    hashMapOffset = fileSizesOffset + (fileNumber * 4)

    #fileOffsets
    fileOffsets = []
    if export_filepath.endswith(".dtt"):
        currentOffset = 0x8000  # Astral Chain does wack stuff with its wtp files
        for i, fp in enumerate(files):
            if os.path.getsize(fp) == 0:
                fileOffsets.append(0)
            else:
                fileOffsets.append(currentOffset)
            currentOffset += os.path.getsize(fp)
            currentOffset = math.ceil(currentOffset/0x8000)*0x8000
    else:
        currentOffset = math.ceil((hashMapOffset + hashMapSize)/16)*16
        for i, fp in enumerate(files):
            if os.path.getsize(fp) == 0:
                fileOffsets.append(0)
            elif fileExtensions[i] == "bnk":
                currentOffset = math.ceil(currentOffset/2048)*2048
                fileOffsets.append(currentOffset)
            else:
                fileOffsets.append(currentOffset)
            currentOffset += os.path.getsize(fp)
            currentOffset = math.ceil(currentOffset/16)*16
    paddingAmount = ((len(files) + 7) // 8) * 8
    padding = b''
    for i in range(paddingAmount - len(files)):
        padding += b'\x00\x00\x00\x00'
    # fileSizes
    fileSizes = []
    for fp in files:
        fileSizes.append(os.path.getsize(fp))

    # WRITE
        # Header
    dat_file = open(export_filepath, 'wb')
    write_string(dat_file, fileID)
    write_Int32(dat_file, fileNumber)
    write_Int32(dat_file, fileOffsetsOffset)
    write_Int32(dat_file, fileExtensionsOffset)
    write_Int32(dat_file, fileNamesOffset)
    write_Int32(dat_file, fileSizesOffset)
    write_Int32(dat_file, hashMapOffset)
    write_buffer(dat_file, 4)


        # fileOffsets
    for value in fileOffsets:
        write_Int32(dat_file, math.ceil(value/8)*8)
    while dat_file.tell() < fileExtensionsOffset:
        dat_file.write(b"\x00")
        # fileExtensions
    for value in fileExtensions:
        write_string(dat_file, value)

        # nameLength
    write_Int32(dat_file, nameLength)
    while dat_file.tell() < fileNamesOffset:
        dat_file.write(b"\x00")
        # fileNames
    for value in fileNames:
        write_string(dat_file, value)
        if len(value) < nameLength:
            write_buffer(dat_file, nameLength - len(value) - 1)
    while dat_file.tell() < fileSizesOffset:
        dat_file.write(b"\x00")
        # fileSizes
    for value in fileSizes:
        write_Int32(dat_file, value)

        # hashMap
    hashMapFile = open(hash_file_path, 'rb')
    hashMap = hashMapFile.read()
    dat_file.write(hashMap)
    hashMapFile.close()
    write_buffer(dat_file, 4)
        # Files
    while dat_file.tell() < fileOffsets[0]:
        dat_file.write(b"\x00")
    for i, fp in enumerate(files):
        fileData = open(fp, 'rb')
        fileContent = fileData.read()
        dat_file.write(fileContent)
        fileData.close()
        if fp == files[-1]:
            while dat_file.tell() % 16 != 0:
                dat_file.write(b"\x00")
            break
        while dat_file.tell() < fileOffsets[i+1]:
            dat_file.write(b"\x00")
        #dat_file.write(padding)

    dat_file.close()
    print('DAT/DTT Export Complete. :>')