/*
 * SPDX-License-Identifier: GPL-3.0-or-later
 */
package com.runicgateway.app.data.repository

import com.runicgateway.app.core.result.ApiResult
import com.runicgateway.app.core.result.safeApiCall
import com.runicgateway.app.data.api.AdminApi
import com.runicgateway.app.data.api.dto.AdminDashboardDto
import com.runicgateway.app.data.api.dto.AdminPostDto
import com.runicgateway.app.data.api.dto.BanRequest
import com.runicgateway.app.data.api.dto.BroadcastRequest
import com.runicgateway.app.data.api.dto.KickRequest
import com.runicgateway.app.data.api.dto.PageRespondRequest
import com.runicgateway.app.data.api.dto.PostCreateRequest
import com.runicgateway.app.data.api.dto.PublishRequest
import com.runicgateway.app.data.api.dto.SiteModeRequest
import com.runicgateway.app.data.api.dto.SiteModeStateDto
import com.runicgateway.app.data.api.dto.SupportPageDto
import com.runicgateway.app.data.api.dto.UnbanRequest
import com.runicgateway.app.data.api.dto.AdminWikiCategoryDto
import com.runicgateway.app.data.api.dto.WikiCategoryRequest
import com.runicgateway.app.data.api.dto.AdminWikiTagDto
import retrofit2.HttpException
import retrofit2.Response
import javax.inject.Inject
import javax.inject.Singleton

/**
 * The M10 staff-operations data source over `/api/v1/admin/…` (PLAN.md §1, §6.4).
 * Every call returns a typed [ApiResult] so a screen renders a clean error/retry
 * rather than crashing — a `403` (role lost since the menu rendered) and a `503`
 * (shard/sidecar offline for the shard-write actions) are both expected outcomes
 * the UI handles, never thrown. Role is authoritative on the server.
 */
@Singleton
class AdminRepository @Inject constructor(
    private val api: AdminApi,
) {
    suspend fun dashboard(): ApiResult<AdminDashboardDto> = safeApiCall { api.dashboard() }

    suspend fun setSiteMode(mode: String): ApiResult<SiteModeStateDto> =
        safeApiCall { api.setSiteMode(SiteModeRequest(mode)) }

    // ── Content: news posts ───────────────────────────────────────────────
    suspend fun posts(): ApiResult<List<AdminPostDto>> = safeApiCall { api.posts() }

    suspend fun createPost(body: PostCreateRequest): ApiResult<AdminPostDto> =
        safeApiCall { api.createPost(body) }

    suspend fun setPostPublished(id: Long, published: Boolean): ApiResult<AdminPostDto> =
        safeApiCall { api.publishPost(id, PublishRequest(published)) }

    suspend fun deletePost(id: Long): ApiResult<Unit> = safeApiCall { api.deletePost(id).requireOk() }

    // ── Content: wiki taxonomy ────────────────────────────────────────────
    suspend fun wikiCategories(): ApiResult<List<AdminWikiCategoryDto>> = safeApiCall { api.wikiCategories() }

    suspend fun createWikiCategory(body: WikiCategoryRequest): ApiResult<AdminWikiCategoryDto> =
        safeApiCall { api.createWikiCategory(body) }

    suspend fun deleteWikiCategory(id: Long): ApiResult<Unit> =
        safeApiCall { api.deleteWikiCategory(id).requireOk() }

    suspend fun wikiTags(): ApiResult<List<AdminWikiTagDto>> = safeApiCall { api.wikiTags() }

    // ── Moderation: shard write plane ─────────────────────────────────────
    suspend fun kick(account: String?, serial: String?): ApiResult<Unit> =
        safeApiCall { api.kick(KickRequest(account, serial)).requireOk() }

    suspend fun ban(account: String?, serial: String?, durationSec: Long?, reason: String?): ApiResult<Unit> =
        safeApiCall { api.ban(BanRequest(account, serial, durationSec, reason)).requireOk() }

    suspend fun unban(account: String): ApiResult<Unit> =
        safeApiCall { api.unban(UnbanRequest(account)).requireOk() }

    suspend fun broadcast(text: String, hue: Int?): ApiResult<Unit> =
        safeApiCall { api.broadcast(BroadcastRequest(text, hue)).requireOk() }

    // ── Support queue: help pages ─────────────────────────────────────────
    suspend fun supportPages(): ApiResult<List<SupportPageDto>> = safeApiCall { api.supportPages() }

    suspend fun respondPage(id: String, message: String, close: Boolean): ApiResult<Unit> =
        safeApiCall { api.respondPage(id, PageRespondRequest(message, close)).requireOk() }

    suspend fun closePage(id: String): ApiResult<Unit> =
        safeApiCall { api.closePage(id).requireOk() }

    /** Turn a bodyless [Response] into a thrown [HttpException] on a non-2xx, so
     *  [safeApiCall] can fold it into an [ApiResult.HttpError] like every other call. */
    private fun Response<Unit>.requireOk() {
        if (!isSuccessful) throw HttpException(this)
    }
}
