import { DateTime } from 'luxon';
import { column, hasMany, belongsTo, SnakeCaseNamingStrategy, computed } from '@adonisjs/lucid/orm';
import HashValue from './hash_value.js';
import Dataset from './dataset.js';
import BaseModel from './base_model.js';
import * as fs from 'fs';
import crypto from 'crypto';
// import Drive from '@ioc:Adonis/Core/Drive';
// import Drive from '@adonisjs/drive';
// import drive from '#services/drive';
import drive from '@adonisjs/drive/services/main';

import type { HasMany } from "@adonisjs/lucid/types/relations";
import type { BelongsTo } from "@adonisjs/lucid/types/relations";
// import { TransactionClientContract } from "@adonisjs/lucid/database";
import { TransactionClientContract } from '@adonisjs/lucid/types/database';





export default class File extends BaseModel {
    // private readonly _data: Uint8Array;
    // private readonly _type: string;
    // private readonly _size: number;

    public static namingStrategy = new SnakeCaseNamingStrategy();
    public static primaryKey = 'id';
    public static table = 'document_files';
    public static selfAssignPrimaryKey = false;

    @column({
        isPrimary: true,
    })
    public id: number;

    @column({})
    public document_id: number;

    @column({})
    public pathName: string;

    @column()
    public label: string;

    @column()
    public comment: string;

    @column()
    public mimeType: string;

    @column()
    public language: string;

    @column()
    public fileSize: number;

    @column()
    public visibleInOai: boolean;

    @column()
    public visibleInFrontdoor: boolean;

    @column()
    public sortOrder: number;

    @column.dateTime({ autoCreate: true })
    public createdAt: DateTime;

    @column.dateTime({ autoCreate: true, autoUpdate: true })
    public updatedAt: DateTime;

    // public function dataset()
    // {
    //     return $this->belongsTo(Dataset::class, 'document_id', 'id');
    // }
    @belongsTo(() => Dataset, {
        foreignKey: 'document_id',
    })
    public dataset: BelongsTo<typeof Dataset>;

    @hasMany(() => HashValue, {
        foreignKey: 'file_id',
    })
    public hashvalues: HasMany<typeof HashValue>;

    @computed({
        serializeAs: 'filePath',
    })
    public get filePath() {
        // return `/storage/app/public/${this.pathName}`;
        return `/storage/app/data/${this.pathName}`;
        // const mainTitle = this.titles?.find((title) => title.type === 'Main');
        // return mainTitle ? mainTitle.value : null;
    }

    @computed({
        serializeAs: 'size',
    })
    public get size() {
        return this.fileSize;
    }

    @computed({
        serializeAs: 'type',
    })
    public get type() {
        return this.mimeType;
    }

    @computed({
        serializeAs: 'name',
    })
    get name(): string {
        return this.label;
    }

    @computed({
        serializeAs: 'lastModified',
    })
    get lastModified(): number {
        return this.updatedAt.toUnixInteger(); //.toFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
    }

    readonly webkitRelativePath: string = '';

    // @computed({
    //     serializeAs: 'fileData',
    // })
    // public get fileData(): string {
    //     try {
    //         const fileContent: Buffer = fs.readFileSync(this.filePath);
    //         // Create a Blob from the file content
    //         // const blob = new Blob([fileContent], { type: this.type }); // Adjust
    //         // let fileSrc = URL.createObjectURL(blob);
    //         // return fileSrc;

    //         // create a JSON string that contains the data in the property "blob"
    //         const json = JSON.stringify({ blob: fileContent.toString('base64') });
    //         return json;
    //     } catch (err) {
    //         // console.error(`Error reading file: ${err}`);
    //         return '';
    //     }
    // }

    public async createHashValues(trx?: TransactionClientContract) {
        const hashtypes: string[] = ['md5', 'sha512'];

        for (const type of hashtypes) {
            const hash = new HashValue();
            hash.type = type;
            const hashString = await this._checksumFile(this.filePath, type); // Assuming getRealHash is a method in the same model
            hash.value = hashString;

            // https://github.com/adonisjs/core/discussions/1872#discussioncomment-132289
            const file: File = this;
            if (trx) {
                await file.useTransaction(trx).related('hashvalues').save(hash); // Save the hash value to the database
            } else {
                await file.related('hashvalues').save(hash); // Save the hash value to the database
            }
        }
    }

    public async delete() {
        if (this.pathName) {
            // Delete file from additional storage
            await drive.use('local').delete(this.pathName);
        }

        // Call the original delete method of the BaseModel to remove the record from the database
        await super.delete();
    }

    private async _checksumFile(path: string, hashName = 'md5'): Promise<string> {
        return new Promise((resolve, reject) => {
            const hash = crypto.createHash(hashName);
            const stream = fs.createReadStream(path);
            stream.on('error', (err) => reject(err));
            stream.on('data', (chunk) => hash.update(chunk));
            stream.on('end', () => resolve(hash.digest('hex')));
        });
    }
}
