import { HttpResponse, HttpResponseOptions } from "@scrypted/types";
import { Response } from "express";
import fs from 'fs';
import net from 'net';
import { join as pathJoin } from 'path';
import { RpcPeer } from "./rpc";

export class HttpResponseImpl implements HttpResponse {
    constructor(public res: Response, public unzippedDir: string, public filesPath: string) {
    }

    [RpcPeer.PROPERTY_PROXY_ONEWAY_METHODS] = [
        'send',
        'sendFile',
        'sendSocket',
    ];
    sent = false;

    #setHeaders(options?: HttpResponseOptions) {
        if (!options?.headers)
            return;
        for (const header of Object.keys(options.headers)) {
            const val = (options.headers as any)[header];
            // null-ish headers will cause something to fail downstream.
            if (val != null)
                this.res.setHeader(header, val);
        }
    }

    send(body: string): void;
    send(body: string, options: HttpResponseOptions): void;
    send(body: Buffer): void;
    send(body: Buffer, options: HttpResponseOptions): void;
    send(body: any, options?: any) {
        this.sent = true;
        if (options?.code)
            this.res.status(options.code);
        this.#setHeaders(options);

        this.res.send(body);
    }

    sendFile(path: string): void;
    sendFile(path: string, options: HttpResponseOptions): void;
    sendFile(path: any, options?: HttpResponseOptions) {
        this.sent = true;
        if (options?.code)
            this.res.status(options.code);
        this.#setHeaders(options);

        let filePath = pathJoin(this.unzippedDir, 'fs', path);
        if (!fs.existsSync(filePath)) {
            filePath = pathJoin(this.filesPath, path);
            if (!fs.existsSync(filePath)) {
                filePath = path;
                if (!fs.existsSync(filePath)) {
                    this.res.status(404);
                    this.res.end();
                    return;
                }
            }
        }

        // prefer etag
        this.res.sendFile(filePath, {
            cacheControl: false,
        });
    }

    sendSocket(socket: net.Socket, options: HttpResponseOptions) {
        this.sent = true;
        if (options?.code)
            this.res.status(options.code);
        this.#setHeaders(options);
        socket.pipe(this.res);
    }
}

export function createResponseInterface(res: Response, unzippedDir: string, filesPath: string): HttpResponseImpl {
    return new HttpResponseImpl(res, unzippedDir, filesPath);
}
