/**
 * Centralized auto-logger for violation timeline entries.
 *
 * Every significant mutation on a violation record should call one of
 * these helpers so the `timeline_entries` JSONB column accumulates a
 * detailed, timestamped audit trail without requiring manual entry.
 */

import { supabase } from "@/integrations/supabase/client";
import { v4 as uuidv4 } from "uuid";

// ── Helpers ─────────────────────────────────────────────────────────

const estNow = () =>
  new Date().toLocaleString("en-US", { timeZone: "America/New_York" });

const isoNow = () => new Date().toISOString();

interface TimelineEntry {
  id: string;
  date?: string;
  created_at: string;
  timestamp_display: string;
  action: string;
  status?: string;
  stage?: string;
  type: "system" | "user";
  details: string;
  description?: string;
  performed_by?: string | null;
  recorded_by_name?: string;
  created_by?: string | null;
  metadata?: Record<string, unknown>;
}

async function currentUserName(): Promise<string> {
  try {
    const {
      data: { user },
    } = await supabase.auth.getUser();
    if (!user) return "System";
    const { data: profile } = await supabase
      .from("profiles")
      .select("full_name")
      .eq("user_id", user.id)
      .maybeSingle();
    return profile?.full_name || user.email || "Unknown User";
  } catch {
    return "System";
  }
}

async function currentUserId(): Promise<string | null> {
  try {
    const {
      data: { user },
    } = await supabase.auth.getUser();
    return user?.id ?? null;
  } catch {
    return null;
  }
}

// ── Core append function ────────────────────────────────────────────

async function appendTimelineEntry(
  violationId: string,
  entry: Omit<TimelineEntry, "id" | "created_at" | "timestamp_display">
) {
  try {
    const { data: violation, error: fetchErr } = await supabase
      .from("violations")
      .select("timeline_entries")
      .eq("id", violationId)
      .single();

    if (fetchErr) {
      console.error("[TimelineLogger] Fetch error:", fetchErr);
      return;
    }

    const current = Array.isArray(violation?.timeline_entries)
      ? (violation.timeline_entries as unknown as TimelineEntry[])
      : [];

    const performedByName =
      typeof entry.metadata?.performed_by_name === "string"
        ? entry.metadata.performed_by_name
        : undefined;

    const newEntry: TimelineEntry = {
      id: uuidv4(),
      created_at: isoNow(),
      date: isoNow(),
      timestamp_display: estNow(),
      status: entry.action,
      stage: entry.action,
      description: entry.details,
      recorded_by_name: performedByName || "System",
      created_by: performedByName || entry.performed_by || "System",
      ...entry,
    };

    const updated = [...current, newEntry];

    const { error: updateErr } = await supabase
      .from("violations")
      .update({
        timeline_entries: JSON.parse(JSON.stringify(updated)),
        updated_at: isoNow(),
      })
      .eq("id", violationId);

    if (updateErr) {
      console.error("[TimelineLogger] Update error:", updateErr);
    }
  } catch (err) {
    console.error("[TimelineLogger] Unexpected error:", err);
  }
}

// ── Public API ──────────────────────────────────────────────────────

/**
 * Log when a brand-new violation record is created.
 */
export async function logViolationCreated(
  violationId: string,
  context: {
    address?: string;
    violationType?: string;
    noticeLevel?: string;
    ownerName?: string;
    associationName?: string;
  }
) {
  const userName = await currentUserName();
  const userId = await currentUserId();

  const parts = [
    `Violation created by ${userName}.`,
    context.address && `Property: ${context.address}.`,
    context.violationType && `Type: ${context.violationType}.`,
    context.noticeLevel && `Initial notice level: ${context.noticeLevel}.`,
    context.ownerName && `Owner: ${context.ownerName}.`,
    context.associationName && `Association: ${context.associationName}.`,
  ].filter(Boolean);

  await appendTimelineEntry(violationId, {
    action: "Violation Created",
    type: "system",
    details: parts.join(" "),
    performed_by: userId,
    metadata: {
      performed_by_name: userName,
      ...context,
    },
  });
}

/**
 * Log when the violation status changes (open → closed, etc.)
 */
export async function logStatusChange(
  violationId: string,
  previousStatus: string | null,
  newStatus: string
) {
  const userName = await currentUserName();
  const userId = await currentUserId();

  const details = previousStatus
    ? `Status changed from "${previousStatus}" to "${newStatus}" by ${userName}.`
    : `Status set to "${newStatus}" by ${userName}.`;

  await appendTimelineEntry(violationId, {
    action: "Status Changed",
    type: "system",
    details,
    performed_by: userId,
    metadata: {
      performed_by_name: userName,
      previous_status: previousStatus,
      new_status: newStatus,
    },
  });
}

/**
 * Log when the notice level / stage advances (1st → 2nd Notice, etc.)
 */
export async function logStageChange(
  violationId: string,
  previousStage: string | null,
  newStage: string
) {
  const userName = await currentUserName();
  const userId = await currentUserId();

  const details = previousStage
    ? `Stage escalated from "${previousStage}" to "${newStage}" by ${userName}.`
    : `Stage set to "${newStage}" by ${userName}.`;

  await appendTimelineEntry(violationId, {
    action: "Stage / Notice Level Changed",
    type: "system",
    details,
    performed_by: userId,
    metadata: {
      performed_by_name: userName,
      previous_stage: previousStage,
      new_stage: newStage,
    },
  });
}

/**
 * Log when a notice PDF is generated / regenerated.
 */
export async function logNoticeGenerated(
  violationId: string,
  context: {
    noticeLevel?: string;
    action?: string;
  }
) {
  const userName = await currentUserName();
  const userId = await currentUserId();

  const details = `${context.noticeLevel || "Notice"} ${
    context.action === "regenerate" ? "regenerated" : "generated"
  } by ${userName}.`;

  await appendTimelineEntry(violationId, {
    action: context.action === "regenerate" ? "Notice Regenerated" : "Notice Generated",
    type: "system",
    details,
    performed_by: userId,
    metadata: {
      performed_by_name: userName,
      notice_level: context.noticeLevel,
    },
  });
}

/**
 * Log a bulk update that touched this violation.
 */
export async function logBulkUpdate(
  violationId: string,
  changes: Record<string, unknown>
) {
  const userName = await currentUserName();
  const userId = await currentUserId();

  const fieldDescriptions: string[] = [];
  if (changes.status) fieldDescriptions.push(`status → "${changes.status}"`);
  if (changes.stage) fieldDescriptions.push(`stage → "${changes.stage}"`);
  if (changes.priority) fieldDescriptions.push(`priority → "${changes.priority}"`);
  if (changes.due_date) fieldDescriptions.push(`due date → ${changes.due_date}`);
  if (changes.violation_date) fieldDescriptions.push(`violation date → ${changes.violation_date}`);
  if (changes.notes) fieldDescriptions.push("notes updated");

  const details = `Bulk update by ${userName}: ${fieldDescriptions.join(", ")}.`;

  await appendTimelineEntry(violationId, {
    action: "Bulk Update Applied",
    type: "system",
    details,
    performed_by: userId,
    metadata: {
      performed_by_name: userName,
      changes,
    },
  });
}

/**
 * Log when a violation is updated through the edit dialog.
 */
export async function logViolationUpdated(
  violationId: string,
  changes: Record<string, { from: unknown; to: unknown }>
) {
  const userName = await currentUserName();
  const userId = await currentUserId();

  const fieldDescriptions = Object.entries(changes).map(
    ([field, { from, to }]) =>
      `${field}: "${from || "—"}" → "${to || "—"}"`
  );

  const details = `Violation updated by ${userName}. Changes: ${fieldDescriptions.join("; ")}.`;

  await appendTimelineEntry(violationId, {
    action: "Violation Updated",
    type: "system",
    details,
    performed_by: userId,
    metadata: {
      performed_by_name: userName,
      changes,
    },
  });
}

/**
 * Log when photos are added to or removed from a violation.
 */
export async function logPhotoChange(
  violationId: string,
  action: "added" | "removed",
  count: number = 1
) {
  const userName = await currentUserName();
  const userId = await currentUserId();

  const verb = action === "added" ? "added" : "removed";
  const noun = count === 1 ? "photo" : "photos";
  const details = `${count} ${noun} ${verb} by ${userName}.`;

  await appendTimelineEntry(violationId, {
    action: action === "added" ? "Photos Added" : "Photo Removed",
    type: "system",
    details,
    performed_by: userId,
    metadata: {
      performed_by_name: userName,
      photo_action: action,
      count,
    },
  });
}
