import { CrudClient } from "../infra/crud-client"
import type { ApiClientOptions } from "../infra/client"
import type { ApiPath, ApiRequestBody } from "../infra/types"
import type { ApiListQueryParams } from "../contracts/types"

export const INSPECTION_ROUTES = {
    CATEGORIES: "/api/inspection-categories",
    CATEGORY_BY_ID: "/api/inspection-categories/{id}",
    INDEX: "/api/inspections",
    BY_ID: "/api/inspections/{id}",
    FROM_TEMPLATE: "/api/inspections/from-template",
    CHANGE_STATUS: "/api/change-inspection-status",
    CHECKPOINT_LABELS: "/api/check-point-label",
    CHECKPOINT_LABEL_BY_ID: "/api/check-point-label/{id}",
    CHECKPOINTS: "/api/inspection-check-points",
    CHECKPOINT_BY_ID: "/api/inspection-check-points/{id}",
    TOGGLE_LABEL_TO_CHECKPOINT: "/api/toggle-label-to-checkpoint",
    CHECKPOINT_CHANGE_STATUS: "/api/inspection-check-points/change-status",
    CHECKPOINT_ADD_ATTACHMENT: "/api/inspection-check-points/add-attachment",
    CHECKPOINT_UPLOAD_MEDIA: "/api/inspection-check-points/{id}/upload-media",
    CHECKPOINT_MEDIA: "/api/inspection-check-points/{id}/media",
} as const satisfies Record<string, ApiPath>

export class InspectionsClient extends CrudClient<
    typeof INSPECTION_ROUTES.INDEX,
    typeof INSPECTION_ROUTES.BY_ID
> {
    constructor(baseUrl?: string, defaultOptions?: ApiClientOptions) {
        super(baseUrl, defaultOptions, INSPECTION_ROUTES.INDEX, INSPECTION_ROUTES.BY_ID)
    }

    // ── Categories ──
    async listCategories(query?: ApiListQueryParams) {
        return this.get(INSPECTION_ROUTES.CATEGORIES, query ? { query } as never : undefined)
    }

    async createCategory(payload: ApiRequestBody<typeof INSPECTION_ROUTES.CATEGORIES, "post">) {
        return this.post(INSPECTION_ROUTES.CATEGORIES, payload)
    }

    async updateCategory(id: string, payload: ApiRequestBody<typeof INSPECTION_ROUTES.CATEGORY_BY_ID, "put">) {
        return this.put(INSPECTION_ROUTES.CATEGORY_BY_ID, payload, { params: { id } })
    }

    async destroyCategory(id: string) {
        return this.delete(INSPECTION_ROUTES.CATEGORY_BY_ID, { params: { id } })
    }

    async getById(id: string) {
        const res = await super.list({ query: { id } } as never)
        return {...res, data: res.data?.[0] }
    }

    async changeStatus(payload: ApiRequestBody<typeof INSPECTION_ROUTES.CHANGE_STATUS, "post">) {
        return this.post(INSPECTION_ROUTES.CHANGE_STATUS, payload)
    }

    async showOne(id: number | string): Promise<{ data: any }> {
        return this.get(`/api/inspections/{id}` as never, { params: { id: String(id) } } as never) as never
    }

    async sign(id: number | string, who: "technician" | "customer", dataUrl: string) {
        return this.post(`/api/inspections/{id}/sign` as never, { who, signature: dataUrl } as never, { params: { id: String(id) } } as never) as never
    }

    /**
     * Upload one or many photos/videos/audio files to a checkpoint via the
     * unified attachments endpoint. The single-file `addCheckpointAttachment`
     * (body-based) above stays available for legacy callers.
     */
    async uploadCheckpointAttachments(
        checkpointId: number | string,
        files: File[],
        caption?: string,
    ): Promise<{ data: Array<{ id: number; url: string; media_type: string; sort_order: number; caption?: string | null }> }> {
        const fd = new FormData()
        files.forEach((f) => fd.append("attachments[]", f))
        if (caption) fd.append("caption", caption)
        const url = `/api/inspection-check-points/${encodeURIComponent(String(checkpointId))}/attachments`
        return (this as any).postFormData(url, fd)
    }

    async destroyCheckpointAttachment(checkpointId: number | string, attachmentId: number | string) {
        return this.delete(
            `/api/inspection-check-points/{id}/attachments/{attachmentId}` as never,
            { params: { id: String(checkpointId), attachmentId: String(attachmentId) } } as never,
        ) as never
    }

    async share(id: number | string): Promise<{ data: { share_token: string; share_url: string; share_enabled_at: string; share_expires_at: string } }> {
        return this.post(`/api/inspections/{id}/share` as never, undefined as never, { params: { id: String(id) } } as never) as never
    }

    async revokeShare(id: number | string): Promise<{ message: string }> {
        return this.post(`/api/inspections/{id}/revoke-share` as never, undefined as never, { params: { id: String(id) } } as never) as never
    }

    async createFromTemplate(payload: {
        template_id: number
        title: string
        customer_id: number | string
        vehicle_id: number | string
        department_id: number | string
        employee_id: number | string
        order_number: string
        date: string
        time: string
        odometer?: number
        note?: string
        inspection_category_id?: number | string
    }) {
        return this.post(INSPECTION_ROUTES.FROM_TEMPLATE as never, payload as never) as never
    }

    // ── Checkpoint Labels ──
    async listCheckpointLabels(query?: ApiListQueryParams) {
        return this.get(INSPECTION_ROUTES.CHECKPOINT_LABELS, query ? { query } as never : undefined)
    }

    async createCheckpointLabel(payload: ApiRequestBody<typeof INSPECTION_ROUTES.CHECKPOINT_LABELS, "post">) {
        return this.post(INSPECTION_ROUTES.CHECKPOINT_LABELS, payload)
    }

    async updateCheckpointLabel(id: string, payload: ApiRequestBody<typeof INSPECTION_ROUTES.CHECKPOINT_LABEL_BY_ID, "put">) {
        return this.put(INSPECTION_ROUTES.CHECKPOINT_LABEL_BY_ID, payload, { params: { id } })
    }

    async destroyCheckpointLabel(id: string) {
        return this.delete(INSPECTION_ROUTES.CHECKPOINT_LABEL_BY_ID, { params: { id } })
    }

    // ── Checkpoints ──
    async listCheckpoints(query?: ApiListQueryParams) {
        return this.get(INSPECTION_ROUTES.CHECKPOINTS, query ? { query } as never : undefined)
    }

    async createCheckpoint(payload: ApiRequestBody<typeof INSPECTION_ROUTES.CHECKPOINTS, "post">) {
        return this.post(INSPECTION_ROUTES.CHECKPOINTS, payload)
    }

    async updateCheckpoint(id: string, payload: ApiRequestBody<typeof INSPECTION_ROUTES.CHECKPOINT_BY_ID, "put">) {
        return this.put(INSPECTION_ROUTES.CHECKPOINT_BY_ID, payload, { params: { id } })
    }

    async destroyCheckpoint(id: string) {
        return this.delete(INSPECTION_ROUTES.CHECKPOINT_BY_ID, { params: { id } })
    }

    async toggleLabelToCheckpoint(payload: ApiRequestBody<typeof INSPECTION_ROUTES.TOGGLE_LABEL_TO_CHECKPOINT, "post">) {
        return this.post(INSPECTION_ROUTES.TOGGLE_LABEL_TO_CHECKPOINT, payload)
    }

    async changeCheckpointStatus(payload: ApiRequestBody<typeof INSPECTION_ROUTES.CHECKPOINT_CHANGE_STATUS, "post">, ) {
        return this.post(INSPECTION_ROUTES.CHECKPOINT_CHANGE_STATUS, payload)
    }

    async addCheckpointAttachment(payload: Record<string, any>) {
        const fd = new FormData()
        for (const [key, value] of Object.entries(payload)) {
            if (value == null) continue
            if (value instanceof File) {
                fd.append(key, value)
            } else {
                fd.append(key, String(value))
            }
        }
        return this.postFormData(INSPECTION_ROUTES.CHECKPOINT_ADD_ATTACHMENT, fd)
    }

    async uploadCheckpointMedia(id: string, payload: Record<string, any>) {
        const fd = new FormData()
        for (const [key, value] of Object.entries(payload)) {
            if (value == null) continue
            if (value instanceof File) {
                fd.append(key, value)
            } else {
                fd.append(key, String(value))
            }
        }
        const url = INSPECTION_ROUTES.CHECKPOINT_UPLOAD_MEDIA.replace("{id}", id)
        return this.postFormData(url, fd)
    }

    async deleteCheckpointMedia(id: string) {
        return this.delete(INSPECTION_ROUTES.CHECKPOINT_MEDIA, { params: { id } })
    }
}
