package com.tt.honeyDue.network

import com.tt.honeyDue.models.*
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*

/**
 * Result type for conditional HTTP requests with ETag support.
 * Used to efficiently check if data has changed on the server.
 */
sealed class ConditionalResult<T> {
    /**
     * Server returned new data (HTTP 200).
     * Includes the new ETag for future conditional requests.
     */
    data class Success<T>(val data: T, val etag: String?) : ConditionalResult<T>()

    /**
     * Data has not changed since the provided ETag (HTTP 304).
     * Client should continue using cached data.
     */
    class NotModified<T> : ConditionalResult<T>()

    /**
     * Request failed with an error.
     */
    data class Error<T>(val message: String, val statusCode: Int? = null) : ConditionalResult<T>()
}

class LookupsApi(private val client: HttpClient = ApiClient.httpClient) {
    private val baseUrl = ApiClient.getBaseUrl()

    suspend fun getResidenceTypes(token: String): ApiResult<List<ResidenceType>> {
        return try {
            val response = client.get("$baseUrl/residences/types/") {
                header("Authorization", "Token $token")
            }

            if (response.status.isSuccess()) {
                ApiResult.Success(response.body())
            } else {
                ApiResult.Error("Failed to fetch residence types", response.status.value)
            }
        } catch (e: Exception) {
            ApiResult.Error(e.message ?: "Unknown error occurred")
        }
    }

    suspend fun getTaskFrequencies(token: String): ApiResult<List<TaskFrequency>> {
        return try {
            val response = client.get("$baseUrl/tasks/frequencies/") {
                header("Authorization", "Token $token")
            }

            if (response.status.isSuccess()) {
                ApiResult.Success(response.body())
            } else {
                ApiResult.Error("Failed to fetch task frequencies", response.status.value)
            }
        } catch (e: Exception) {
            ApiResult.Error(e.message ?: "Unknown error occurred")
        }
    }

    suspend fun getTaskPriorities(token: String): ApiResult<List<TaskPriority>> {
        return try {
            val response = client.get("$baseUrl/tasks/priorities/") {
                header("Authorization", "Token $token")
            }

            if (response.status.isSuccess()) {
                ApiResult.Success(response.body())
            } else {
                ApiResult.Error("Failed to fetch task priorities", response.status.value)
            }
        } catch (e: Exception) {
            ApiResult.Error(e.message ?: "Unknown error occurred")
        }
    }

    suspend fun getTaskCategories(token: String): ApiResult<List<TaskCategory>> {
        return try {
            val response = client.get("$baseUrl/tasks/categories/") {
                header("Authorization", "Token $token")
            }

            if (response.status.isSuccess()) {
                ApiResult.Success(response.body())
            } else {
                ApiResult.Error("Failed to fetch task categories", response.status.value)
            }
        } catch (e: Exception) {
            ApiResult.Error(e.message ?: "Unknown error occurred")
        }
    }

    suspend fun getContractorSpecialties(token: String): ApiResult<List<ContractorSpecialty>> {
        return try {
            val response = client.get("$baseUrl/contractors/specialties/") {
                header("Authorization", "Token $token")
            }

            if (response.status.isSuccess()) {
                ApiResult.Success(response.body())
            } else {
                ApiResult.Error("Failed to fetch contractor specialties", response.status.value)
            }
        } catch (e: Exception) {
            ApiResult.Error(e.message ?: "Unknown error occurred")
        }
    }

    suspend fun getStaticData(token: String? = null): ApiResult<StaticDataResponse> {
        return try {
            val response = client.get("$baseUrl/static_data/") {
                // Token is optional - endpoint is public
                token?.let { header("Authorization", "Token $it") }
            }

            if (response.status.isSuccess()) {
                ApiResult.Success(response.body())
            } else {
                ApiResult.Error("Failed to fetch static data", response.status.value)
            }
        } catch (e: Exception) {
            ApiResult.Error(e.message ?: "Unknown error occurred")
        }
    }

    /**
     * Fetches unified seeded data (all lookups + task templates) with ETag support.
     *
     * @param currentETag The ETag from a previous response. If provided and data hasn't changed,
     *                    server returns 304 Not Modified.
     * @param token Optional auth token (endpoint is public).
     * @return ConditionalResult with data and new ETag, NotModified if unchanged, or Error.
     */
    suspend fun getSeededData(
        currentETag: String? = null,
        token: String? = null
    ): ConditionalResult<SeededDataResponse> {
        return try {
            val response: HttpResponse = client.get("$baseUrl/static_data/") {
                // Token is optional - endpoint is public
                token?.let { header("Authorization", "Token $it") }
                // Send If-None-Match header for conditional request
                currentETag?.let { header("If-None-Match", it) }
            }

            when {
                response.status == HttpStatusCode.NotModified -> {
                    // Data hasn't changed since provided ETag
                    ConditionalResult.NotModified()
                }
                response.status.isSuccess() -> {
                    // Data has changed or first request - get new data and ETag
                    val data: SeededDataResponse = response.body()
                    val newETag = response.headers["ETag"]
                    ConditionalResult.Success(data, newETag)
                }
                else -> {
                    ConditionalResult.Error(
                        "Failed to fetch seeded data",
                        response.status.value
                    )
                }
            }
        } catch (e: Exception) {
            ConditionalResult.Error(e.message ?: "Unknown error occurred")
        }
    }
}
