import Vapor

struct TryFilesMiddleware: AsyncMiddleware {

    let publicDirectory: String

    func respond(to request: Request, chainingTo next: any AsyncResponder) async throws -> Response {
        let relativePath = request.url.path
        let potentialPaths = [
            publicDirectory + relativePath,
            publicDirectory + relativePath + ".html",
            publicDirectory + relativePath + "/1.html"
        ]

        for path in potentialPaths {
            var isDirectory: ObjCBool = false
            guard FileManager.default.fileExists(atPath: path, isDirectory: &isDirectory),
                    !isDirectory.boolValue else {
                continue
            }
            let url = URL(fileURLWithPath: path)
            let data = try Data(contentsOf: url)
            let response = Response(status: .ok, body: .init(data: data))
            response.headers.replaceOrAdd(name: .contentType, value: url.mimeType)
            response.headers.replaceOrAdd(name: .contentLength, value: "\(data.count)")
            return response
        }
        return .init(status: .notFound)
    }
}

private extension URL {

    var mimeType: String {
        switch pathExtension.lowercased() {
        case "html": return "text/html"
        case "css": return "text/css"
        case "js": return "application/javascript"
        case "json": return "application/json"
        case "xml": return "application/xml"
        case "txt": return "text/plain"

        case "jpg", "jpeg": return "image/jpeg"
        case "png": return "image/png"
        case "gif": return "image/gif"
        case "svg": return "image/svg+xml"
        case "webp": return "image/webp"
        case "ico": return "image/x-icon"

        case "pdf": return "application/pdf"
        case "zip": return "application/zip"
        case "tar": return "application/x-tar"
        case "gz": return "application/gzip"
        case "rar": return "application/vnd.rar"

        case "mp3": return "audio/mpeg"
        case "wav": return "audio/wav"
        case "ogg": return "audio/ogg"

        case "mp4": return "video/mp4"
        case "mov": return "video/quicktime"
        case "avi": return "video/x-msvideo"
        case "webm": return "video/webm"

        default: return "application/octet-stream" // Default binary data type
        }
    }
}
