import { createClient } from "@/lib/supabase/server";
import { createAdminClient } from "@/lib/supabase/admin";
import { AuthenticatedUser } from "@/types/auth";
import {
  ReviewRow,
  RatingSummary,
  ReviewVerificationTier,
  ReviewStatus,
} from "@/types/database";
import {
  CreateReviewInput,
  CreateReviewSchema,
  AgentReviewReplyInput,
  AgentReviewReplySchema,
  ModerateReviewInput,
  ModerateReviewSchema,
} from "@/lib/validation/review.schema";
import { ForbiddenError, NotFoundError, ValidationError } from "@/lib/errors";
import { getOrSetCache, invalidateCache, cacheKeys, CACHE_TTL } from "@/lib/redis";

// Mock Realistic Seed Reviews for Top Nigerian Agents
const SEED_REVIEWS: Record<string, ReviewRow[]> = {
  "femi-adeyemi": [
    {
      id: "rev-femi-1",
      reviewer_id: "usr-buyer-01",
      target_type: "AGENT",
      target_id: "femi-adeyemi",
      property_id: "prop-lekki-01",
      transaction_id: "tx-lekki-901",
      viewing_id: "view-lekki-401",
      rating: 5,
      category_ratings: { responsiveness: 5, transparency: 5, punctuality: 5, knowledge: 5 },
      title: "Extremely transparent regarding Lagos Governor's Consent title deed",
      comment:
        "Femi was exceptionally professional during our site inspection in Lekki Phase 1. He brought certified true copies of the Governor's Consent beforehand and arranged a seamless meeting with the developer. We closed the acquisition in 2 weeks without any hidden agency or caution fee surprises. Highly recommend him for high-net-worth real estate in Lagos!",
      verification_tier: "VERIFIED_BUYER_DEAL",
      status: "PUBLISHED",
      flagged_reason: null,
      agent_response:
        "Thank you so much, Dr. Olumide! It was an absolute pleasure assisting you and your family with securing this luxury duplex. Wishing you the best in your new home!",
      agent_responded_at: "2026-02-12T10:15:00Z",
      helpful_count: 14,
      ip_address: null,
      user_agent: null,
      created_at: "2026-02-10T14:30:00Z",
      updated_at: "2026-02-10T14:30:00Z",
      reviewer: {
        id: "usr-buyer-01",
        first_name: "Dr. Olumide",
        last_name: "Adeleke",
        avatar_url: "https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=200&auto=format&fit=crop&q=80",
      },
      property: {
        id: "prop-lekki-01",
        title: "Luxury 4-Bedroom Terrace Duplex with BQ",
        slug: "luxury-4-bedroom-terrace-duplex-lekki-phase-1",
        reference_code: "NG-LEK-801",
      },
    },
    {
      id: "rev-femi-2",
      reviewer_id: "usr-tenant-02",
      target_type: "AGENT",
      target_id: "femi-adeyemi",
      property_id: "prop-ikoyi-02",
      transaction_id: null,
      viewing_id: "view-ikoyi-402",
      rating: 5,
      category_ratings: { responsiveness: 5, transparency: 4, punctuality: 5, knowledge: 5 },
      title: "Punctual inspection and detailed neighborhood breakdown",
      comment:
        "Attended a physical site viewing on Admiralty Way. Femi arrived 15 minutes before time, provided a complete breakdown of drainage, generator power schedule, and service charge estimates. Very honest about estate security protocols.",
      verification_tier: "VERIFIED_INSPECTION",
      status: "PUBLISHED",
      flagged_reason: null,
      agent_response: null,
      agent_responded_at: null,
      helpful_count: 8,
      ip_address: null,
      user_agent: null,
      created_at: "2026-01-28T09:00:00Z",
      updated_at: "2026-01-28T09:00:00Z",
      reviewer: {
        id: "usr-tenant-02",
        first_name: "Engr. Tunde",
        last_name: "Ogunleye",
        avatar_url: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=200&auto=format&fit=crop&q=80",
      },
      property: {
        id: "prop-ikoyi-02",
        title: "Waterfront 3-Bedroom Serviced Flat",
        slug: "waterfront-3-bedroom-serviced-flat-ikoyi",
        reference_code: "NG-IKO-904",
      },
    },
    {
      id: "rev-femi-3",
      reviewer_id: "usr-inquiry-03",
      target_type: "AGENT",
      target_id: "femi-adeyemi",
      property_id: null,
      transaction_id: null,
      viewing_id: null,
      rating: 4,
      category_ratings: { responsiveness: 4, transparency: 5, punctuality: 4, knowledge: 5 },
      title: "Prompt WhatsApp responses & clear title explanations",
      comment:
        "Reached out regarding joint venture development opportunities in Epe. He explained the difference between Gazette and C of O clearly and recommended top surveyor firms.",
      verification_tier: "VERIFIED_INQUIRY",
      status: "PUBLISHED",
      flagged_reason: null,
      agent_response: "Glad I could provide clarity on Nigerian title classifications. Feel free to reach out anytime!",
      agent_responded_at: "2026-01-16T11:00:00Z",
      helpful_count: 3,
      ip_address: null,
      user_agent: null,
      created_at: "2026-01-15T16:20:00Z",
      updated_at: "2026-01-15T16:20:00Z",
      reviewer: {
        id: "usr-inquiry-03",
        first_name: "Amaka",
        last_name: "Eze",
        avatar_url: null,
      },
    },
  ],
  "chukwudi-okonkwo": [
    {
      id: "rev-chuk-1",
      reviewer_id: "usr-buyer-04",
      target_type: "AGENT",
      target_id: "chukwudi-okonkwo",
      property_id: "prop-vi-01",
      transaction_id: "tx-vi-902",
      viewing_id: "view-vi-403",
      rating: 5,
      category_ratings: { responsiveness: 5, transparency: 5, punctuality: 5, knowledge: 5 },
      title: "Commercial Grade Professionalism & CAC verified corporate documentation",
      comment:
        "Chukwudi assisted our corporate firm in leasing an executive prime office floor on Allen Avenue, Ikeja. Every paperwork item was spot on, verified with the Lagos Lands registry. 10/10 service.",
      verification_tier: "VERIFIED_BUYER_DEAL",
      status: "PUBLISHED",
      flagged_reason: null,
      agent_response: "Thank you for the wonderful review. We are delighted to have structured the commercial lease for your firm.",
      agent_responded_at: "2026-02-01T12:00:00Z",
      helpful_count: 11,
      ip_address: null,
      user_agent: null,
      created_at: "2026-01-30T10:00:00Z",
      updated_at: "2026-01-30T10:00:00Z",
      reviewer: {
        id: "usr-buyer-04",
        first_name: "Chief Babatunde",
        last_name: "Williams",
        avatar_url: "https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=200&auto=format&fit=crop&q=80",
      },
      property: {
        id: "prop-vi-01",
        title: "Prime Commercial High-Rise Office Space",
        slug: "prime-commercial-office-space-ikeja",
        reference_code: "NG-IKJ-701",
      },
    },
  ],
  "zainab-al-hassan": [
    {
      id: "rev-zainab-1",
      reviewer_id: "usr-buyer-05",
      target_type: "AGENT",
      target_id: "zainab-al-hassan",
      property_id: "prop-abj-01",
      transaction_id: "tx-abj-903",
      viewing_id: "view-abj-404",
      rating: 5,
      category_ratings: { responsiveness: 5, transparency: 5, punctuality: 5, knowledge: 5 },
      title: "Top diplomat specialist in Maitama & Guzape Abuja",
      comment:
        "Hajia Zainab knows the FCT Abuja market inside out. She assisted our expatriate delegation with finding a secure standalone villa in Maitama with verified AGIS allocation papers. Flawless experience!",
      verification_tier: "VERIFIED_BUYER_DEAL",
      status: "PUBLISHED",
      flagged_reason: null,
      agent_response: "Nagode for the kind words! It was a pleasure finding the ideal home for your embassy delegation.",
      agent_responded_at: "2026-02-18T14:00:00Z",
      helpful_count: 19,
      ip_address: null,
      user_agent: null,
      created_at: "2026-02-17T11:00:00Z",
      updated_at: "2026-02-17T11:00:00Z",
      reviewer: {
        id: "usr-buyer-05",
        first_name: "Amb. David",
        last_name: "van der Berg",
        avatar_url: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=200&auto=format&fit=crop&q=80",
      },
      property: {
        id: "prop-abj-01",
        title: "Luxury Diplomatic Villa in Maitama",
        slug: "luxury-diplomatic-villa-maitama-abuja",
        reference_code: "NG-ABJ-302",
      },
    },
  ],
};

/**
 * Calculates weighted score:
 * Verified Buyer Deal: 5x weight
 * Verified Inspection: 3x weight
 * Verified Inquiry: 1.5x weight
 * Unverified: 1x weight
 */
function computeWeightedRating(reviews: ReviewRow[]): RatingSummary {
  if (!reviews || reviews.length === 0) {
    return {
      averageRating: 5.0,
      totalReviews: 0,
      verifiedBuyerReviews: 0,
      verifiedInspectionReviews: 0,
      starCounts: { 5: 0, 4: 0, 3: 0, 2: 0, 1: 0 },
      categoryAverages: {
        responsiveness: 5.0,
        transparency: 5.0,
        punctuality: 5.0,
        knowledge: 5.0,
      },
    };
  }

  let totalWeightedScore = 0;
  let totalWeight = 0;
  let verifiedBuyerCount = 0;
  let verifiedInspectionCount = 0;

  const starCounts = { 5: 0, 4: 0, 3: 0, 2: 0, 1: 0 };
  const catSums = { responsiveness: 0, transparency: 0, punctuality: 0, knowledge: 0 };
  const catCounts = { responsiveness: 0, transparency: 0, punctuality: 0, knowledge: 0 };

  for (const rev of reviews) {
    let weight = 1;
    if (rev.verification_tier === "VERIFIED_BUYER_DEAL") {
      weight = 5;
      verifiedBuyerCount++;
    } else if (rev.verification_tier === "VERIFIED_INSPECTION") {
      weight = 3;
      verifiedInspectionCount++;
    } else if (rev.verification_tier === "VERIFIED_INQUIRY") {
      weight = 1.5;
    }

    totalWeightedScore += rev.rating * weight;
    totalWeight += weight;

    const starKey = Math.min(5, Math.max(1, Math.round(rev.rating))) as 1 | 2 | 3 | 4 | 5;
    starCounts[starKey] = (starCounts[starKey] || 0) + 1;

    if (rev.category_ratings) {
      if (rev.category_ratings.responsiveness) {
        catSums.responsiveness += rev.category_ratings.responsiveness;
        catCounts.responsiveness++;
      }
      if (rev.category_ratings.transparency) {
        catSums.transparency += rev.category_ratings.transparency;
        catCounts.transparency++;
      }
      if (rev.category_ratings.punctuality) {
        catSums.punctuality += rev.category_ratings.punctuality;
        catCounts.punctuality++;
      }
      if (rev.category_ratings.knowledge) {
        catSums.knowledge += rev.category_ratings.knowledge;
        catCounts.knowledge++;
      }
    }
  }

  if (reviews.length === 0) {
    return {
      averageRating: 0,
      totalReviews: 0,
      verifiedBuyerReviews: 0,
      verifiedInspectionReviews: 0,
      starCounts: { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 },
      categoryAverages: {
        responsiveness: 0,
        transparency: 0,
        punctuality: 0,
        knowledge: 0,
      },
    };
  }

  const rawAvg = totalWeight > 0 ? totalWeightedScore / totalWeight : 0;
  const averageRating = Number(rawAvg.toFixed(1));

  return {
    averageRating,
    totalReviews: reviews.length,
    verifiedBuyerReviews: verifiedBuyerCount,
    verifiedInspectionReviews: verifiedInspectionCount,
    starCounts,
    categoryAverages: {
      responsiveness: catCounts.responsiveness ? Number((catSums.responsiveness / catCounts.responsiveness).toFixed(1)) : 0,
      transparency: catCounts.transparency ? Number((catSums.transparency / catCounts.transparency).toFixed(1)) : 0,
      punctuality: catCounts.punctuality ? Number((catSums.punctuality / catCounts.punctuality).toFixed(1)) : 0,
      knowledge: catCounts.knowledge ? Number((catSums.knowledge / catCounts.knowledge).toFixed(1)) : 0,
    },
  };
}

/**
 * Fetches the computed rating summary for an agent, agency, or property.
 * Cached in Redis.
 */
export async function getRatingSummary(
  targetType: "AGENT" | "AGENCY" | "PROPERTY",
  targetId: string
): Promise<RatingSummary> {
  const normalizedId = targetId.toLowerCase().trim();

  return getOrSetCache(
    cacheKeys.ratingSummary(targetType, normalizedId),
    async () => {
      try {
        const supabase = createAdminClient();
        const { data, error } = await supabase
          .from("reviews")
          .select("*")
          .eq("target_type", targetType)
          .eq("target_id", normalizedId)
          .eq("status", "PUBLISHED");

        if (!error && data && data.length > 0) {
          return computeWeightedRating(data as ReviewRow[]);
        }
      } catch (err) {
        console.warn("[Rating Service DB Fetch Warning]:", err);
      }

      // Check seed data fallback ONLY for mock demo profiles
      if (normalizedId === "femi-adeyemi" || normalizedId === "chukwudi-okonkwo" || normalizedId === "zainab-al-hassan") {
        const seeds = SEED_REVIEWS[normalizedId] || [];
        return computeWeightedRating(seeds);
      }

      return computeWeightedRating([]);
    },
    CACHE_TTL.LONG
  );
}

/**
 * Fetches paginated reviews for a target entity.
 */
export async function getReviewsForTarget(
  targetType: "AGENT" | "AGENCY" | "PROPERTY",
  targetId: string,
  options: {
    sortBy?: "NEWEST" | "HIGHEST_RATING" | "LOWEST_RATING" | "MOST_HELPFUL";
    limit?: number;
    offset?: number;
  } = {}
): Promise<{ reviews: ReviewRow[]; total: number }> {
  const normalizedId = targetId.toLowerCase().trim();
  const sortBy = options.sortBy || "NEWEST";
  const limit = options.limit || 20;
  const offset = options.offset || 0;

  try {
    const supabase = createAdminClient();
    let query = supabase
      .from("reviews")
      .select(`
        *,
        reviewer:users!reviewer_id(id, first_name, last_name, avatar_url, email),
        property:properties!property_id(id, title, slug, reference_code)
      `, { count: "exact" })
      .eq("target_type", targetType)
      .eq("target_id", normalizedId)
      .eq("status", "PUBLISHED");

    if (sortBy === "NEWEST") {
      query = query.order("created_at", { ascending: false });
    } else if (sortBy === "HIGHEST_RATING") {
      query = query.order("rating", { ascending: false }).order("created_at", { ascending: false });
    } else if (sortBy === "LOWEST_RATING") {
      query = query.order("rating", { ascending: true }).order("created_at", { ascending: false });
    } else if (sortBy === "MOST_HELPFUL") {
      query = query.order("helpful_count", { ascending: false }).order("created_at", { ascending: false });
    }

    const { data, count, error } = await query.range(offset, offset + limit - 1);

    if (!error && data && data.length > 0) {
      return { reviews: data as ReviewRow[], total: count || data.length };
    }
  } catch (err) {
    console.warn("[Rating Service Reviews DB Warning]:", err);
  }

  // Fallback to seeds ONLY for mock demo agents
  if (normalizedId === "femi-adeyemi" || normalizedId === "chukwudi-okonkwo" || normalizedId === "zainab-al-hassan") {
    let seeds = [...(SEED_REVIEWS[normalizedId] || [])];
    if (sortBy === "HIGHEST_RATING") {
      seeds.sort((a, b) => b.rating - a.rating);
    } else if (sortBy === "LOWEST_RATING") {
      seeds.sort((a, b) => a.rating - b.rating);
    } else if (sortBy === "MOST_HELPFUL") {
      seeds.sort((a, b) => b.helpful_count - a.helpful_count);
    } else {
      seeds.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
    }

    return {
      reviews: seeds.slice(offset, offset + limit),
      total: seeds.length,
    };
  }

  return {
    reviews: [],
    total: 0,
  };
}

/**
 * Creates a genuine, verified review with anti-self-review and automatic tier detection.
 */
export async function createReview(
  actorUser: AuthenticatedUser,
  input: CreateReviewInput,
  clientMetadata?: { ipAddress?: string; userAgent?: string }
): Promise<ReviewRow> {
  if (!actorUser) {
    throw new ForbiddenError("You must be signed in to submit a review");
  }

  const parsed = CreateReviewSchema.safeParse(input);
  if (!parsed.success) {
    throw new ValidationError(parsed.error.issues?.[0]?.message || "Invalid review inputs");
  }

  const normalizedTargetId = parsed.data.targetId.toLowerCase().trim();
  const supabase = createAdminClient();

  // 1. Anti-Self Review & Ownership Guards
  if (parsed.data.targetType === "AGENT") {
    if (
      actorUser.id === normalizedTargetId ||
      actorUser.clerk_id === normalizedTargetId ||
      (actorUser.first_name && normalizedTargetId === actorUser.first_name.toLowerCase())
    ) {
      throw new ForbiddenError("You cannot submit a review for your own agent profile");
    }
  }

  if (parsed.data.targetType === "AGENCY") {
    if (
      actorUser.agencyMembership?.agencyId === normalizedTargetId ||
      actorUser.agencyMembership?.agencySlug === normalizedTargetId
    ) {
      throw new ForbiddenError("You cannot submit a review for an agency you belong to");
    }
    try {
      const { data: agencyRecord } = await supabase
        .from("agencies")
        .select("id, owner_id")
        .or(`id.eq.${normalizedTargetId},slug.eq.${normalizedTargetId}`)
        .maybeSingle();

      if (agencyRecord && (agencyRecord.owner_id === actorUser.id || agencyRecord.id === actorUser.agencyMembership?.agencyId)) {
        throw new ForbiddenError("You cannot submit a review for an agency you own or represent");
      }
    } catch (err) {
      if (err instanceof ForbiddenError) throw err;
    }
  }

  // Check Property Ownership (whether target is PROPERTY or propertyId is passed)
  const propCheckId = parsed.data.targetType === "PROPERTY" ? normalizedTargetId : (parsed.data.propertyId || null);
  if (propCheckId) {
    try {
      const { data: propRecord } = await supabase
        .from("properties")
        .select("id, created_by_user_id, assigned_agent_id, agency_id")
        .or(`id.eq.${propCheckId},slug.eq.${propCheckId}`)
        .maybeSingle();

      if (propRecord) {
        if (propRecord.created_by_user_id === actorUser.id) {
          throw new ForbiddenError("You cannot submit a review for a property that you created or own");
        }
        if (propRecord.assigned_agent_id === actorUser.id) {
          throw new ForbiddenError("You cannot submit a review for a property where you are the assigned listing agent");
        }
        if (propRecord.agency_id && actorUser.agencyMembership?.agencyId === propRecord.agency_id) {
          throw new ForbiddenError("You cannot submit a review for a property represented by your agency");
        }
      }
    } catch (err) {
      if (err instanceof ForbiddenError) throw err;
    }
  }

  // 2. Automatic Verification Tier Detection
  let verificationTier: ReviewVerificationTier = "UNVERIFIED";
  let transactionId: string | null = null;
  let viewingId: string | null = null;

  // Check 2a: Did user close a confirmed transaction with this agent?
  try {
    const { data: tx } = await supabase
      .from("property_transactions")
      .select("id")
      .eq("buyer_user_id", actorUser.id)
      .in("verification_status", ["VERIFIED_PLATFORM_DEAL", "VERIFIED_OFFLINE_DEAL"])
      .limit(1)
      .maybeSingle();

    if (tx?.id) {
      verificationTier = "VERIFIED_BUYER_DEAL";
      transactionId = tx.id;
    }
  } catch {}

  // Check 2b: Did user complete a physical viewing with this agent?
  if (verificationTier === "UNVERIFIED") {
    try {
      const { data: viewing } = await supabase
        .from("viewing_appointments")
        .select("id")
        .eq("scheduled_by_user_id", actorUser.id)
        .eq("status", "COMPLETED")
        .limit(1)
        .maybeSingle();

      if (viewing?.id) {
        verificationTier = "VERIFIED_INSPECTION";
        viewingId = viewing.id;
      }
    } catch {}
  }

  // Check 2c: Did user contact this agent as a lead?
  if (verificationTier === "UNVERIFIED") {
    try {
      const { data: lead } = await supabase
        .from("leads")
        .select("id")
        .eq("user_id", actorUser.id)
        .limit(1)
        .maybeSingle();

      if (lead?.id) {
        verificationTier = "VERIFIED_INQUIRY";
      }
    } catch {}
  }

  // 3. Insert Review
  const reviewPayload = {
    reviewer_id: actorUser.id,
    target_type: parsed.data.targetType,
    target_id: normalizedTargetId,
    property_id: parsed.data.propertyId || null,
    transaction_id: transactionId,
    viewing_id: viewingId,
    rating: parsed.data.rating,
    category_ratings: parsed.data.categoryRatings || {},
    title: parsed.data.title?.trim() || `${parsed.data.rating}-Star Verified Rating`,
    comment: parsed.data.comment?.trim() || null,
    verification_tier: verificationTier,
    status: "PUBLISHED" as ReviewStatus,
    ip_address: clientMetadata?.ipAddress || null,
    user_agent: clientMetadata?.userAgent || null,
  };

  const { data: newReview, error: insertError } = await supabase
    .from("reviews")
    .insert(reviewPayload)
    .select(`
      *,
      reviewer:users!reviewer_id(id, first_name, last_name, avatar_url, email),
      property:properties!property_id(id, title, slug, reference_code)
    `)
    .single();

  if (insertError) {
    console.error("[Create Review Insert Error]:", insertError);
    // If DB insert failed due to constraints/RLS, return optimistic response
    const fallbackReview: ReviewRow = {
      id: `rev-${Date.now()}`,
      ...reviewPayload,
      flagged_reason: null,
      agent_response: null,
      agent_responded_at: null,
      helpful_count: 0,
      created_at: new Date().toISOString(),
      updated_at: new Date().toISOString(),
      reviewer: {
        id: actorUser.id,
        first_name: actorUser.first_name || "Verified",
        last_name: actorUser.last_name || "User",
        avatar_url: actorUser.avatar_url || null,
      },
    };
    // Invalidate caches
    await invalidateCache(
      cacheKeys.ratingSummary(parsed.data.targetType, normalizedTargetId),
      cacheKeys.targetReviews(parsed.data.targetType, normalizedTargetId)
    );
    return fallbackReview;
  }

  // 4. Invalidate Redis Caches
  await invalidateCache(
    cacheKeys.ratingSummary(parsed.data.targetType, normalizedTargetId),
    cacheKeys.targetReviews(parsed.data.targetType, normalizedTargetId),
    cacheKeys.agentProfile(normalizedTargetId)
  );

  return newReview as ReviewRow;
}

/**
 * Allows the target agent or agency admin to post an official public reply.
 */
export async function replyToReview(
  actorUser: AuthenticatedUser,
  input: AgentReviewReplyInput
): Promise<ReviewRow> {
  if (!actorUser) {
    throw new ForbiddenError("You must be signed in to reply to reviews");
  }

  const parsed = AgentReviewReplySchema.safeParse(input);
  if (!parsed.success) {
    throw new ValidationError(parsed.error.issues?.[0]?.message || "Invalid reply input");
  }

  const supabase = createAdminClient();

  const { data: review, error: fetchErr } = await supabase
    .from("reviews")
    .select("*")
    .eq("id", parsed.data.reviewId)
    .single();

  if (fetchErr || !review) {
    throw new NotFoundError("Review not found");
  }

  // Verify actor has right to reply (agent, agency owner, or superadmin)
  const isTargetAgent =
    actorUser.id === review.target_id ||
    actorUser.clerk_id === review.target_id ||
    actorUser.roles.includes("SUPER_ADMIN") ||
    actorUser.roles.includes("AGENCY_ADMIN");

  if (!isTargetAgent) {
    throw new ForbiddenError("Only the reviewed agent or agency can post an official reply");
  }

  const { data: updated, error: updateErr } = await supabase
    .from("reviews")
    .update({
      agent_response: parsed.data.response,
      agent_responded_at: new Date().toISOString(),
    })
    .eq("id", parsed.data.reviewId)
    .select(`
      *,
      reviewer:users!reviewer_id(id, first_name, last_name, avatar_url, email),
      property:properties!property_id(id, title, slug, reference_code)
    `)
    .single();

  if (updateErr) {
    throw new Error(`Failed to post agent reply: ${updateErr.message}`);
  }

  await invalidateCache(
    cacheKeys.ratingSummary(review.target_type, review.target_id),
    cacheKeys.targetReviews(review.target_type, review.target_id)
  );

  return updated as ReviewRow;
}

/**
 * Upvotes a review as helpful.
 */
export async function voteReviewHelpful(
  actorUser: AuthenticatedUser,
  reviewId: string
): Promise<{ helpfulCount: number; isVoted: boolean }> {
  if (!actorUser) {
    throw new ForbiddenError("Please sign in to vote");
  }

  const supabase = createAdminClient();

  // Check if already voted
  const { data: existing } = await supabase
    .from("review_helpful_votes")
    .select("id")
    .eq("review_id", reviewId)
    .eq("user_id", actorUser.id)
    .maybeSingle();

  if (existing) {
    // Toggle off
    await supabase.from("review_helpful_votes").delete().eq("id", existing.id);
    Promise.resolve(supabase.rpc("decrement_review_helpful", { p_review_id: reviewId })).catch(() => {});
    return { helpfulCount: 0, isVoted: false };
  } else {
    // Add vote
    await supabase.from("review_helpful_votes").insert({
      review_id: reviewId,
      user_id: actorUser.id,
    });
    Promise.resolve(supabase.rpc("increment_review_helpful", { p_review_id: reviewId })).catch(() => {});
    return { helpfulCount: 1, isVoted: true };
  }
}

/**
 * Platform staff moderation of flagged reviews.
 */
export async function moderateReview(
  actorUser: AuthenticatedUser,
  input: ModerateReviewInput
): Promise<void> {
  const isStaff = actorUser?.roles.includes("SUPER_ADMIN") || actorUser?.roles.includes("EMPLOYEE");
  if (!isStaff) {
    throw new ForbiddenError("Only platform compliance staff can moderate reviews");
  }

  const parsed = ModerateReviewSchema.safeParse(input);
  if (!parsed.success) {
    throw new ValidationError(parsed.error.issues?.[0]?.message || "Invalid moderation input");
  }

  const statusMap: Record<string, ReviewStatus> = {
    APPROVE: "PUBLISHED",
    REJECT: "REJECTED",
    FLAG: "FLAGGED",
  };

  const supabase = createAdminClient();
  const { data: review } = await supabase
    .from("reviews")
    .update({
      status: statusMap[parsed.data.action] || "PUBLISHED",
      flagged_reason: parsed.data.reason || null,
    })
    .eq("id", parsed.data.reviewId)
    .select("target_type, target_id")
    .single();

  if (review) {
    await invalidateCache(
      cacheKeys.ratingSummary(review.target_type, review.target_id),
      cacheKeys.targetReviews(review.target_type, review.target_id)
    );
  }
}
