package com.gh.gamecenter.mock.mockinizer

import com.gh.gamecenter.mock.mockwebserver3.MockResponse
import com.gh.gamecenter.mock.mockwebserver3.MockWebServer
import okhttp3.HttpUrl
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response


class MockinizerInterceptor(
    private val mocks: Map<RequestFilter, MockResponse> = emptyMap(),
    private val mockServer: MockWebServer,
    private val log: Logger = DebugLogger
) : Interceptor {


    private fun matchMockForFilterUrl(request: Request): MockResponse? {
        val urlPath = request.url().uri().path
        for ((requestFilter, mockResponse) in mocks) {
            if (requestFilter.path == urlPath) {
                return mockResponse
            }
        }
        return null
    }

    override fun intercept(chain: Interceptor.Chain): Response {

        fun findMockResponse(request: Request): MockResponse? {
            matchMockForFilterUrl(request)
            return with(RequestFilter.from(request, log)) {
                val foundMockResponse = matchMockForFilterUrl(request)
                    ?: mocks[this]
                    ?: mocks[this.copy(body = null)]
                    ?: mocks[this.copy(headers = null)]
                    ?: mocks[this.copy(body = null, headers = null)]

                if (foundMockResponse == null) {
                    log.d("No mocks found for $request")
                } else {
                    log.d(
                        "Found Mock response: $foundMockResponse " +
                                "for request: $request"
                    )
                }

                foundMockResponse
            }
        }

        fun Interceptor.Chain.findServer(): HttpUrl =
            when (findMockResponse(request())) {
                is MockResponse -> {
                    request().url().newBuilder()
                        .host(mockServer.hostName)
                        .port(mockServer.port)
//                .scheme("http") //TODO: make http - https configurable
                        .build()
                }
                else ->
                    request().url()
            }

        return with(chain) {
            proceed(
                request().newBuilder()
                    .url(findServer())
                    .build()
            )
        }
    }

}


