import { isRecord, serverRequest } from "./serverConnection";

export interface ServerCommunityAsset {
  id?: number;
  assetType: "image" | "video" | "project" | "workflow" | "asset" | "cover" | "other";
  title?: string | null;
  url?: string | null;
  ossKey?: string | null;
  metadata?: Record<string, unknown>;
  sortOrder?: number;
}

export interface ServerCommunityCase {
  id: number;
  userId?: number;
  username?: string | null;
  projectId?: string | null;
  title: string;
  description?: string | null;
  coverUrl?: string | null;
  tags: string[];
  metadata: Record<string, unknown>;
  status: "pending" | "approved" | "rejected";
  reviewNote?: string | null;
  publishedAt?: string | null;
  copyCount: number;
  favoriteCount: number;
  likeCount: number;
  isFavorited: boolean;
  isLiked: boolean;
  createdAt: string;
  updatedAt: string;
  assets: ServerCommunityAsset[];
}

export interface PublishCommunityCaseInput {
  projectId?: string | null;
  title: string;
  description?: string | null;
  coverUrl?: string | null;
  tags?: string[];
  metadata?: Record<string, unknown>;
  assets?: Array<{
    assetType?: ServerCommunityAsset["assetType"];
    title?: string;
    url?: string;
    ossKey?: string;
    metadata?: Record<string, unknown>;
    sortOrder?: number;
  }>;
}

function toNumber(value: unknown, fallback = 0): number {
  const numeric = typeof value === "number" ? value : Number(value);
  return Number.isFinite(numeric) ? numeric : fallback;
}

function toStringValue(value: unknown, fallback = ""): string {
  if (typeof value === "string") return value.trim() || fallback;
  if (typeof value === "number" && Number.isFinite(value)) return String(value);
  return fallback;
}

function toStringArray(value: unknown): string[] {
  if (!Array.isArray(value)) return [];
  const result: string[] = [];
  for (const item of value) {
    const text = toStringValue(item);
    if (text) result.push(text);
  }
  return result;
}

function toMetadata(value: unknown): Record<string, unknown> {
  return isRecord(value) ? value : {};
}

function normalizeAsset(raw: unknown): ServerCommunityAsset {
  const asset = isRecord(raw) ? raw : {};
  const assetType = toStringValue(asset.assetType ?? asset.asset_type ?? asset.type, "other");
  return {
    id: Number.isFinite(Number(asset.id)) ? Number(asset.id) : undefined,
    assetType:
      assetType === "image" ||
      assetType === "video" ||
      assetType === "image" ||
      assetType === "project" ||
      assetType === "workflow" ||
      assetType === "asset" ||
      assetType === "cover"
        ? assetType
        : "other",
    title: toStringValue(asset.title) || null,
    url: toStringValue(asset.url) || null,
    ossKey: toStringValue(asset.ossKey ?? asset.oss_key) || null,
    metadata: toMetadata(asset.metadata),
    sortOrder: toNumber(asset.sortOrder ?? asset.sort_order),
  };
}

function normalizeCase(raw: unknown): ServerCommunityCase {
  const item = isRecord(raw) ? raw : {};
  const status = toStringValue(item.status, "pending");
  return {
    id: toNumber(item.id),
    userId: Number.isFinite(Number(item.userId ?? item.user_id)) ? Number(item.userId ?? item.user_id) : undefined,
    username: toStringValue(item.username) || null,
    projectId: toStringValue(item.projectId ?? item.project_id) || null,
    title: toStringValue(item.title, "未命名案例"),
    description: toStringValue(item.description) || null,
    coverUrl: toStringValue(item.coverUrl ?? item.cover_url) || null,
    tags: toStringArray(item.tags),
    metadata: toMetadata(item.metadata),
    status: status === "approved" || status === "rejected" ? status : "pending",
    reviewNote: toStringValue(item.reviewNote ?? item.review_note) || null,
    publishedAt: toStringValue(item.publishedAt ?? item.published_at) || null,
    copyCount: toNumber(item.copyCount ?? item.copy_count),
    favoriteCount: toNumber(item.favoriteCount ?? item.favorite_count),
    likeCount: toNumber(item.likeCount ?? item.like_count),
    isFavorited: Boolean(item.isFavorited ?? item.is_favorited),
    isLiked: Boolean(item.isLiked ?? item.is_liked),
    createdAt: toStringValue(item.createdAt ?? item.created_at, new Date().toISOString()),
    updatedAt: toStringValue(item.updatedAt ?? item.updated_at, new Date().toISOString()),
    assets: Array.isArray(item.assets) ? item.assets.map(normalizeAsset) : [],
  };
}

function extractCases(payload: unknown): ServerCommunityCase[] {
  if (Array.isArray(payload)) return payload.map(normalizeCase);
  if (!isRecord(payload)) return [];
  const rows = payload.cases ?? payload.items;
  return Array.isArray(rows) ? rows.map(normalizeCase) : [];
}

export const communityClient = {
  async listApprovedCases(
    params: number | { limit?: number; q?: string; category?: string; tag?: string; sort?: string } = 30,
  ): Promise<ServerCommunityCase[]> {
    const search = new URLSearchParams();
    if (typeof params === "number") {
      search.set("limit", String(params));
    } else {
      search.set("limit", String(params.limit ?? 30));
      if (params.q) search.set("q", params.q);
      if (params.category && params.category !== "全部") search.set("category", params.category);
      if (params.tag) search.set("tag", params.tag);
      if (params.sort) search.set("sort", params.sort);
    }
    return extractCases(await serverRequest<unknown>(`community/cases?${search.toString()}`));
  },

  async listMyCases(): Promise<ServerCommunityCase[]> {
    return extractCases(await serverRequest<unknown>("community/me/cases"));
  },

  async listCasesForReview(status: "" | ServerCommunityCase["status"] = "pending"): Promise<ServerCommunityCase[]> {
    const search = new URLSearchParams();
    if (status) search.set("status", status);
    const query = search.toString();
    return extractCases(await serverRequest<unknown>(`admin/community/cases${query ? `?${query}` : ""}`));
  },

  async publishCase(input: PublishCommunityCaseInput): Promise<ServerCommunityCase> {
    const payload = await serverRequest<{ case: unknown }>("community/cases", {
      method: "POST",
      body: input,
    });
    return normalizeCase(payload.case);
  },

  async updateReviewStatus(
    caseId: number | string,
    status: Exclude<ServerCommunityCase["status"], "pending">,
    reviewNote: string,
  ): Promise<ServerCommunityCase> {
    const payload = await serverRequest<{ case: unknown }>(`admin/community/cases/${encodeURIComponent(String(caseId))}/status`, {
      method: "PATCH",
      body: { status, reviewNote, review_note: reviewNote },
    });
    return normalizeCase(payload.case);
  },

  async copyCase(caseId: number, input?: { projectId?: string; name?: string; ossKey?: string }): Promise<void> {
    await serverRequest(`community/cases/${caseId}/copy`, {
      method: "POST",
      body: input || {},
    });
  },

  async setReaction(
    caseId: number,
    reactionType: "favorite" | "like",
    active: boolean,
  ): Promise<{ favoriteCount: number; likeCount: number; isFavorited: boolean; isLiked: boolean }> {
    const payload = await serverRequest<{ stats: unknown }>(`community/cases/${caseId}/reactions`, {
      method: "POST",
      body: { reactionType, active },
    });
    const stats = isRecord(payload.stats) ? payload.stats : {};
    return {
      favoriteCount: toNumber(stats.favoriteCount),
      likeCount: toNumber(stats.likeCount),
      isFavorited: Boolean(stats.isFavorited),
      isLiked: Boolean(stats.isLiked),
    };
  },
};
