import { Injectable } from "@nestjs/common";
import { Response } from "express";
import { AdminSearchDto } from "src/time-and-attendance/attachments/dtos/search-filters.dto";
import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service";
import { resolveAttachmentsRoot } from "src/time-and-attendance/attachments/config/attachment.config";
import * as path from 'node:path';
import { promises as fsp } from 'node:fs';
import { createReadStream } from "node:fs";
import { fileTypeFromFile } from "file-type";
import { Result } from "src/common/errors/result-error.factory";

@Injectable()
export class AttachmentGetService {
    constructor(
        private readonly prisma: PrismaPostgresService,

    ) { }

    async getListVariants(id: string): Promise<Result<any, string>> {
        const num_id = Number(id);
        if (!Number.isFinite(num_id)) return { success: false, error: 'INVALID_ATTACHMENTS' };
        const variants = await this.prisma.client.attachmentVariants.findMany({
            where: { attachment_id: num_id },
            orderBy: { variant: 'asc' },
            select: { variant: true, bytes: true, width: true, height: true, path: true, created_at: true },
        });
        return { success: true, data: variants };
    }

    async searchAttachmentWithFilters(dto: AdminSearchDto): Promise<Result<any, string>> {
        const where: any = {};
        if (dto.owner_type) where.owner_type = dto.owner_type;
        if (dto.owner_id) where.owner_id = dto.owner_id;

        if (dto.date_from || dto.date_to) {
            where.created_at = {};
            if (dto.date_from) where.created_at.gte = new Date(dto.date_from + 'T00:00:00Z');
            if (dto.date_to) where.created_at.lte = new Date(dto.date_to + 'T23:59:59Z');
        }

        const page = dto.page ?? 1;
        const page_size = dto.page_size ?? 50;
        const skip = (page - 1) * page_size;
        const take = page_size;

        const [items, total] = await this.prisma.client.$transaction([
            this.prisma.client.attachments.findMany({
                where,
                orderBy: { created_at: 'desc' },
                skip, take,
                include: {
                    blob: {
                        select: { mime: true, size: true, storage_path: true, sha256: true },
                    },
                },
            }),
            this.prisma.client.attachments.count({ where }),
        ]);

        return { success: true, data: { page, page_size: take, total, items } };
    }


    async findAttachmentById(id: string, variant: string | undefined, res: Response): Promise<Result<boolean, string>> {
        const num_id = Number(id);
        if (!Number.isFinite(num_id)) return { success: false, error: 'INVALID_ATTACHMENTS' };

        const attachment = await this.prisma.client.attachments.findUnique({
            where: { id: num_id },
            include: { blob: true },
        });
        if (!attachment) return { success: false, error: 'ATTACHMENT_NOT_FOUND' };

        const relative = variant ? `${attachment.blob.storage_path}.${variant}` : attachment.blob.storage_path;
        const abs = path.join(resolveAttachmentsRoot(), relative);

        let stat;
        try {
            stat = await fsp.stat(abs);
        } catch {
            return { success: false, error: 'INVALID_FILE_PATH' };
        }

        let mime = attachment.blob.mime;
        try {
            const kind = await fileTypeFromFile(abs);
            if (kind?.mime) mime = kind.mime;
        } catch { }
        res.set('Content-Type', mime);
        res.set('Content-Length', String(stat.size));
        res.set('ETag', `"sha256-${attachment.blob.sha256}${variant ? '.' + variant : ''}"`);
        res.set('Last-Modified', stat.mtime.toUTCString());
        res.set('Cache-Control', 'private, max-age=31536000, immutable');
        res.set('X-Content-Type-Options', 'nosniff');

        createReadStream(abs).pipe(res);
        return { success: true, data: true };
    }

}
