/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * This source file is part of the Cangjie project, licensed under Apache-2.0
 * with Runtime Library Exception.
 *
 * See https://cangjie-lang.cn/pages/LICENSE for license information.
 */

package stdx.net.http

import std.net.StreamingSocket
import std.sync.Mutex
import stdx.crypto.common.Certificate

public class HttpContext {
    let writerMtx = Mutex()
    // response flushed by user
    var responseFlushedByUser: Bool = false
    // response flushed by user and with chunked
    var responseFlushedWithChunked: Bool = false

    // such as upgraded to websocket
    var upgraded: Bool = false
    var responded: Bool = false

    var _httpConn: ?HttpEngineConn = None

    HttpContext(let _request: HttpRequest, let _responseBuilder: HttpResponseBuilder) {}

    mut prop httpConn: HttpEngineConn {
        get() {
            _httpConn ?? throw HttpException("Internal error, conn in HttpContext is None.")
        }
        set(v) {
            _httpConn = v
        }
    }

    func reset(): Unit {
        responseFlushedByUser = false
        responseFlushedWithChunked = false
        upgraded = false
        responded = false
        _request.reset()
        _responseBuilder.reset()
    }

    public func isClosed(): Bool {
        return httpConn.isClosed()
    }


    public prop request: HttpRequest {
        get() {
            return _request
        }
    }

    public prop responseBuilder: HttpResponseBuilder {
        get() {
            return _responseBuilder
        }
    }

    public prop clientCertificate: ?Array<Certificate> {
        get() {
            match (httpConn.clientCertificate) {
                case Some(c) =>
                    if (c.isEmpty()) {
                        None
                    } else {
                        c
                    }
                case None => None
            }
        }
    }
}

public func upgrade(ctx: HttpContext): StreamingSocket {
    synchronized(ctx.writerMtx) {
        if (ctx.upgraded) {
            throw HttpException("Should not call upgrade more than once.")
        }
        if (ctx.responseFlushedByUser) {
            throw HttpException("Should not upgrade after write response.")
        }
        if (ctx.responded) {
            throw HttpException("Already responded.")
        }
        ctx.httpConn.writeUpgradeResponse(ctx)
        ctx.upgraded = true
    }
    ctx.request._body = HttpEmptyBody.INSTANCE
    return ctx.httpConn.getSocket()
}