import { revalidatePath } from "next/cache";
import { createAdminClient } from "@/lib/supabase/admin";
import { AuthenticatedUser } from "@/types/auth";
import { PropertyRow, PropertyStatus } from "@/types/database";
import { logAuditEvent } from "./audit.service";
import { getOrSetCache, invalidateCache, cacheKeys, CACHE_TTL } from "@/lib/redis";
import { purgePropertyCaches, getCustomProperties, saveCustomProperty } from "./property.service";
import { serverAnalytics as analytics } from "@/lib/analytics/server";
import { sendPropertyModerationResult, sendAgencyVerificationEmails } from "@/lib/services/email.service";

/**
 * List properties for platform staff moderation review.
 * Uses elevated admin client to bypass RLS and view all pending submissions across the platform.
 */
export async function listModerationProperties(
  actor: AuthenticatedUser,
  filters: {
    status?: string;
    search?: string;
    page?: number;
    limit?: number;
  } = {}
) {
  const page = filters.page || 1;
  const limit = filters.limit || 50;
  const offset = (page - 1) * limit;
  const targetStatus = filters.status || "PENDING_REVIEW";

  // 1. Fetch DB properties using administrative service role
  let dbProperties: any[] = [];
  try {
    const supabase = createAdminClient();
    let query = supabase
      .from("properties")
      .select(`
        *,
        state:states(name),
        lga:lgas(name),
        district:districts(name),
        agency:agencies(id, name, cac_rc_number, is_verified),
        creator:users!properties_created_by_user_id_fkey(id, first_name, last_name, email, phone_number),
        images:property_images(id, url, is_primary, caption, display_order, sort_order),
        documents:property_documents(id, title, document_type, storage_path)
      `, { count: "exact" })
      .is("deleted_at", null);

    if (targetStatus && targetStatus !== "ALL") {
      query = query.eq("status", targetStatus);
    }

    if (filters.search) {
      query = query.or(
        `title.ilike.%${filters.search}%,reference_code.ilike.%${filters.search}%`
      );
    }

    query = query.order("created_at", { ascending: false });
    const { data, error } = await query;
    if (error) {
      console.warn("[Moderation DB Query Error]:", error);
    } else if (data) {
      dbProperties = data;
    }
  } catch (err) {
    console.warn("[Moderation DB Query Exception]:", err);
  }

  // 2. Fetch custom properties from Redis
  const customProperties = await getCustomProperties();

  // Merge and deduplicate by id
  const propertyMap = new Map<string, any>();
  for (const p of dbProperties) {
    if (p?.id) propertyMap.set(p.id, p);
  }
  for (const p of customProperties) {
    if (p?.id && !propertyMap.has(p.id)) {
      propertyMap.set(p.id, p);
    }
  }

  let allList = Array.from(propertyMap.values());

  // Filter by status
  if (targetStatus && targetStatus !== "ALL") {
    allList = allList.filter((p) => p.status === targetStatus);
  }

  // Filter by search
  if (filters.search) {
    const q = filters.search.toLowerCase();
    allList = allList.filter(
      (p) =>
        p.title?.toLowerCase().includes(q) ||
        p.reference_code?.toLowerCase().includes(q) ||
        p.description?.toLowerCase().includes(q) ||
        p.creator?.email?.toLowerCase().includes(q)
    );
  }

  // Sort descending by created_at
  allList.sort((a, b) => {
    const timeA = new Date(a.created_at || 0).getTime();
    const timeB = new Date(b.created_at || 0).getTime();
    return timeB - timeA;
  });

  const totalCount = allList.length;
  const paginated = allList.slice(offset, offset + limit);

  return {
    properties: paginated,
    totalCount,
    page,
    totalPages: Math.ceil(totalCount / limit) || 1,
  };
}

/**
 * Aggregates moderation metrics for the staff desk (Cached in Redis for 30s)
 */
export async function getModerationMetrics() {
  return getOrSetCache(
    cacheKeys.moderationMetrics(),
    async () => {
      const propertyMap = new Map<string, { status: string }>();

      // 1. Check Redis custom properties
      const custom = await getCustomProperties();
      for (const p of custom) {
        if (p?.id && p?.status) {
          propertyMap.set(p.id, { status: p.status });
        }
      }

      // 2. Check Database properties with elevated service client
      try {
        const supabase = createAdminClient();
        const { data: dbProperties, error } = await supabase
          .from("properties")
          .select("id, status")
          .is("deleted_at", null);

        if (!error && dbProperties) {
          for (const p of dbProperties) {
            if (p?.id && p?.status) {
              propertyMap.set(p.id, { status: p.status });
            }
          }
        }
      } catch (err) {
        console.warn("[Moderation Metrics Notice]:", err);
      }

      const all = Array.from(propertyMap.values());
      const pendingReview = all.filter((p) => p.status === "PENDING_REVIEW").length;
      const published = all.filter((p) => p.status === "PUBLISHED").length;
      const rejected = all.filter((p) => p.status === "REJECTED").length;
      const totalProperties = all.length;

      return {
        pendingReview,
        published,
        rejected,
        totalProperties,
      };
    },
    CACHE_TTL.SHORT
  );
}

/**
 * Approve property listing and publish live
 */
export async function approveProperty(
  actor: AuthenticatedUser,
  propertyId: string,
  notes?: string | null
): Promise<{ success: boolean; property?: PropertyRow; error?: string }> {
  let propertyRecord: any = null;
  const now = new Date().toISOString();

  try {
    const supabase = createAdminClient();

    // Ensure actor exists in users table for foreign key reference
    if (actor?.id) {
      await supabase.from("users").upsert({
        id: actor.id,
        clerk_id: actor.clerk_id || actor.id,
        email: actor.email,
        first_name: actor.first_name || "",
        last_name: actor.last_name || "",
        is_active: true,
        updated_at: now,
      }, { onConflict: "id" });
    }

    const { data: updated, error: updateError } = await supabase
      .from("properties")
      .update({
        status: "PUBLISHED",
        is_verified: true,
        published_at: now,
        moderated_by_user_id: actor.id,
        moderated_at: now,
        rejection_reason: null,
        updated_at: now,
      })
      .eq("id", propertyId)
      .select("*")
      .single();

    if (updated) {
      propertyRecord = updated;
    } else if (updateError) {
      console.warn("[Approve DB Error]:", updateError);
    }
  } catch (err) {
    console.warn("[Approve DB Notice]:", err);
  }

  // Update in Redis custom properties
  const custom = await getCustomProperties();
  const target = custom.find((p) => p.id === propertyId);
  if (target) {
    target.status = "PUBLISHED";
    target.is_verified = true;
    target.published_at = now;
    target.moderated_by_user_id = actor.id;
    target.moderated_at = now;
    target.rejection_reason = null;
    target.updated_at = now;
    await saveCustomProperty(target);
    propertyRecord = propertyRecord || target;
  }

  if (!propertyRecord) {
    return { success: false, error: "Property listing not found" };
  }

  await Promise.all([
    purgePropertyCaches({ slug: propertyRecord?.slug, id: propertyId }),
    invalidateCache(cacheKeys.moderationMetrics()),
  ]);

  analytics.trackPropertyPublished(
    {
      property_id: propertyId,
      property_type: propertyRecord.property_type,
      listing_type: propertyRecord.listing_type,
      state_id: propertyRecord.state_id,
      price: propertyRecord.price,
    },
    propertyRecord.created_by_user_id || actor.id
  ).catch(() => {});

  await logAuditEvent({
    actor,
    action: "property.approved",
    entityType: "property",
    entityId: propertyId,
    newState: propertyRecord,
  });

  // Fetch creator info to dispatch approval email
  if (propertyRecord.creator?.email || propertyRecord.created_by_user_id) {
    sendPropertyModerationResult({
      property: {
        id: propertyRecord.id,
        title: propertyRecord.title,
        reference_code: propertyRecord.reference_code,
        slug: propertyRecord.slug,
      },
      creator: propertyRecord.creator || {
        email: actor.email,
        first_name: actor.first_name,
        last_name: actor.last_name,
      },
      action: "APPROVED",
    }).catch(() => {});
  }

  return { success: true, property: propertyRecord as PropertyRow };
}

/**
 * Reject property listing with reason
 */
export async function rejectProperty(
  actor: AuthenticatedUser,
  propertyId: string,
  rejectionReason: string
): Promise<{ success: boolean; property?: PropertyRow; error?: string }> {
  let propertyRecord: any = null;
  const now = new Date().toISOString();

  try {
    const supabase = createAdminClient();

    // Ensure actor exists in users table for foreign key reference
    if (actor?.id) {
      await supabase.from("users").upsert({
        id: actor.id,
        clerk_id: actor.clerk_id || actor.id,
        email: actor.email,
        first_name: actor.first_name || "",
        last_name: actor.last_name || "",
        is_active: true,
        updated_at: now,
      }, { onConflict: "id" });
    }

    const { data: updated, error: updateError } = await supabase
      .from("properties")
      .update({
        status: "REJECTED",
        rejection_reason: rejectionReason,
        moderated_by_user_id: actor.id,
        moderated_at: now,
        updated_at: now,
      })
      .eq("id", propertyId)
      .select("*")
      .single();

    if (updated) {
      propertyRecord = updated;
    } else if (updateError) {
      console.warn("[Reject DB Error]:", updateError);
    }
  } catch (err) {
    console.warn("[Reject DB Notice]:", err);
  }

  // Update in Redis custom properties
  const custom = await getCustomProperties();
  const target = custom.find((p) => p.id === propertyId);
  if (target) {
    target.status = "REJECTED";
    target.rejection_reason = rejectionReason;
    target.moderated_by_user_id = actor.id;
    target.moderated_at = now;
    target.updated_at = now;
    await saveCustomProperty(target);
    propertyRecord = propertyRecord || target;
  }

  if (!propertyRecord) {
    return { success: false, error: "Property listing not found" };
  }

  await Promise.all([
    purgePropertyCaches({ slug: propertyRecord?.slug, id: propertyId }),
    invalidateCache(cacheKeys.moderationMetrics()),
  ]);

  await logAuditEvent({
    actor,
    action: "property.rejected",
    entityType: "property",
    entityId: propertyId,
    newState: propertyRecord,
  });

  // Fetch creator info to dispatch rejection email with feedback
  if (propertyRecord.creator?.email || propertyRecord.created_by_user_id) {
    sendPropertyModerationResult({
      property: {
        id: propertyRecord.id,
        title: propertyRecord.title,
        reference_code: propertyRecord.reference_code,
        slug: propertyRecord.slug,
      },
      creator: propertyRecord.creator || {
        email: actor.email,
        first_name: actor.first_name,
        last_name: actor.last_name,
      },
      action: "REJECTED",
      notes: rejectionReason,
    }).catch(() => {});
  }

  return { success: true, property: propertyRecord as PropertyRow };
}

/**
 * Verify Real Estate Agency Corporate Status
 */
export async function verifyAgencyCorporateStatus(
  actor: AuthenticatedUser,
  agencyId: string
): Promise<{ success: boolean; error?: string }> {
  const supabase = createAdminClient();

  const { data: agency, error } = await supabase
    .from("agencies")
    .update({
      is_verified: true,
      updated_at: new Date().toISOString(),
    })
    .eq("id", agencyId)
    .select("*")
    .single();

  if (error || !agency) {
    return { success: false, error: error?.message || "Failed to verify agency" };
  }

  await logAuditEvent({
    actor,
    action: "agency.verified",
    entityType: "agency",
    entityId: agencyId,
    newState: { is_verified: true },
  });

  await invalidateCache(cacheKeys.agencyDetails(agencyId));

  // Fetch agency owner
  const { data: owner } = await supabase
    .from("users")
    .select("id, clerk_id, email, first_name, last_name")
    .eq("id", agency.owner_id)
    .maybeSingle();

  if (owner?.clerk_id) {
    await invalidateCache(cacheKeys.userSession(owner.clerk_id));
  }
  if (agency.owner_id) {
    await invalidateCache(cacheKeys.userSession(agency.owner_id));
  }

  // Revalidate relevant pages so user immediately sees approval banner & activation screen
  try {
    revalidatePath("/dashboard");
    revalidatePath("/dashboard/agency");
    revalidatePath("/dashboard/billing");
    revalidatePath("/admin/agency-verifications");
    revalidatePath("/agencies");
  } catch (revalErr) {
    console.warn("[Agency Moderation Revalidate Warning]:", revalErr);
  }

  sendAgencyVerificationEmails({
    agency: {
      id: agency.id,
      name: agency.name,
      cac_rc_number: agency.cac_rc_number,
    },
    owner,
    type: "VERIFIED",
  }).catch(() => {});

  return { success: true };
}
