import { Comment, StepLink, StepType, TripStep, UserRole } from "@/types";
import { Database } from "@/integrations/supabase/types";

type Json = Database["public"]["Tables"]["trip_steps"]["Row"]["links"];
type TripStepRow = Database["public"]["Tables"]["trip_steps"]["Row"];
type TripStepInsert = Database["public"]["Tables"]["trip_steps"]["Insert"];
type TripStepUpdate = Database["public"]["Tables"]["trip_steps"]["Update"];
type CommentRow = Database["public"]["Tables"]["comments"]["Row"];

const VALID_STEP_TYPES: StepType[] = [
  "transport",
  "meal",
  "accommodation",
  "activity",
  "break",
  "ticket",
  "other",
];

const VALID_USER_ROLES: UserRole[] = ["planner", "traveler"];

/**
 * Safely parse a Json value into StepLink[].
 * Returns [] if value is null, not an array, or contains malformed items.
 */
export function parseStepLinks(value: Json | null | undefined): StepLink[] {
  if (!value || !Array.isArray(value)) return [];
  const result: StepLink[] = [];
  for (const item of value) {
    if (
      item &&
      typeof item === "object" &&
      !Array.isArray(item) &&
      typeof (item as Record<string, unknown>).url === "string"
    ) {
      const obj = item as Record<string, unknown>;
      result.push({
        url: String(obj.url),
        title: typeof obj.title === "string" ? obj.title : "Lien",
      });
    }
  }
  return result;
}

/**
 * Serialize StepLink[] into a Json-safe value for Supabase.
 */
export function serializeStepLinks(value: StepLink[] | undefined | null): Json {
  if (!value || !Array.isArray(value)) return null;
  const cleaned = value
    .filter((l) => l && typeof l.url === "string" && l.url.length > 0)
    .map((l) => ({ url: l.url, title: l.title || "Lien" }));
  return cleaned.length > 0 ? cleaned : null;
}

/**
 * Safely parse a database step_type string into the StepType union.
 * Falls back to "activity" when invalid.
 */
export function parseStepType(value: string | null | undefined): StepType {
  return VALID_STEP_TYPES.find((candidate) => candidate === value) ?? "activity";
}

/**
 * Safely parse a database role string into the UserRole union.
 * Falls back to "traveler" when invalid.
 */
export function parseUserRole(value: string | null | undefined): UserRole {
  return VALID_USER_ROLES.find((candidate) => candidate === value) ?? "traveler";
}

/**
 * Map a Supabase comment row to the frontend Comment model.
 */
export function mapCommentFromDB(row: CommentRow): Comment {
  return {
    id: row.id,
    userId: row.user_id,
    userName: row.user_name,
    content: row.content,
    createdAt: row.created_at,
  };
}

export function mapCommentsFromDB(rows: CommentRow[] | null | undefined): Comment[] {
  if (!rows || !Array.isArray(rows)) return [];
  return rows
    .slice()
    .sort((a, b) => a.created_at.localeCompare(b.created_at) || a.id.localeCompare(b.id))
    .map(mapCommentFromDB);
}

/**
 * Map a Supabase trip_steps row (optionally with joined comments) into TripStep.
 */
export function mapTripStepFromDB(
  row: TripStepRow & { comments?: CommentRow[] | null }
): TripStep {
  return {
    id: row.id,
    imagePath: row.image_path,
    tripId: row.trip_id,
    day: row.day,
    time: row.time,
    location: row.location,
    activity: row.activity,
    price: row.price ?? undefined,
    distance: row.distance ?? undefined,
    link: row.link ?? undefined,
    links: parseStepLinks(row.links),
    validationStatus: row.validation_status,
    isPublished: row.is_published ?? false,
    comments: mapCommentsFromDB(row.comments),
    stepType: parseStepType(row.step_type),
    startTime: row.start_time ?? undefined,
    endTime: row.end_time ?? undefined,
    description: row.description ?? undefined,
    transportType: row.transport_type ?? undefined,
    referenceNumber: row.reference_number ?? undefined,
    departureName: row.departure_name ?? undefined,
    arrivalName: row.arrival_name ?? undefined,
    estimatedDuration: row.estimated_duration ?? undefined,
    restaurantName: row.restaurant_name ?? undefined,
    cuisineType: row.cuisine_type ?? undefined,
    budget: row.budget ?? undefined,
    accommodationName: row.accommodation_name ?? undefined,
    roomType: row.room_type ?? undefined,
    checkInTime: row.check_in_time ?? undefined,
    checkOutTime: row.check_out_time ?? undefined,
    reservationNumber: row.reservation_number ?? undefined,
    rating: row.rating ?? undefined,
    activityType: row.activity_type ?? undefined,
    guideName: row.guide_name ?? undefined,
    walkingLevel: row.walking_level ?? undefined,
    breakPurpose: row.break_purpose ?? undefined,
    internalNotes: row.internal_notes ?? undefined,
  };
}

/**
 * Build a typed Insert payload for trip_steps from a frontend step.
 */
export function mapTripStepToInsert(
  tripId: string,
  stepData: Omit<TripStep, "id" | "comments" | "tripId">
): TripStepInsert {
  return {
    trip_id: tripId,
    image_path: stepData.imagePath ?? null,
    day: stepData.day,
    time: stepData.time || stepData.startTime || "",
    location: stepData.location,
    activity: stepData.activity,
    price: stepData.price ?? null,
    distance: stepData.distance ?? null,
    link: stepData.link ?? null,
    links: serializeStepLinks(stepData.links),
    validation_status: stepData.validationStatus ?? "pending",
    is_published: stepData.isPublished ?? false,
    step_type: parseStepType(stepData.stepType),
    start_time: stepData.startTime ?? null,
    end_time: stepData.endTime ?? null,
    description: stepData.description ?? null,
    transport_type: stepData.transportType ?? null,
    reference_number: stepData.referenceNumber ?? null,
    departure_name: stepData.departureName ?? null,
    arrival_name: stepData.arrivalName ?? null,
    estimated_duration: stepData.estimatedDuration ?? null,
    restaurant_name: stepData.restaurantName ?? null,
    cuisine_type: stepData.cuisineType ?? null,
    budget: stepData.budget ?? null,
    accommodation_name: stepData.accommodationName ?? null,
    room_type: stepData.roomType ?? null,
    check_in_time: stepData.checkInTime ?? null,
    check_out_time: stepData.checkOutTime ?? null,
    reservation_number: stepData.reservationNumber ?? null,
    rating: stepData.rating ?? null,
    activity_type: stepData.activityType ?? null,
    guide_name: stepData.guideName ?? null,
    walking_level: stepData.walkingLevel ?? null,
    break_purpose: stepData.breakPurpose ?? null,
    internal_notes: stepData.internalNotes ?? null,
  };
}

/**
 * Build a typed Update payload for trip_steps from a partial frontend step.
 * Only defined fields are included.
 */
export function mapTripStepToUpdate(stepData: Partial<TripStep>): TripStepUpdate {
  const update: TripStepUpdate = { updated_at: new Date().toISOString() };
  if (stepData.imagePath !== undefined) update.image_path = stepData.imagePath || null;
  if (stepData.day !== undefined) update.day = stepData.day;
  if (stepData.time !== undefined) update.time = stepData.time;
  if (stepData.location !== undefined) update.location = stepData.location;
  if (stepData.activity !== undefined) update.activity = stepData.activity;
  if (stepData.price !== undefined) update.price = stepData.price ?? null;
  if (stepData.distance !== undefined) update.distance = stepData.distance ?? null;
  if (stepData.link !== undefined) update.link = stepData.link ?? null;
  if (stepData.links !== undefined) update.links = serializeStepLinks(stepData.links);
  if (stepData.validationStatus !== undefined) update.validation_status = stepData.validationStatus;
  if (stepData.isPublished !== undefined) update.is_published = stepData.isPublished;
  if (stepData.stepType !== undefined) update.step_type = parseStepType(stepData.stepType);
  if (stepData.startTime !== undefined) update.start_time = stepData.startTime ?? null;
  if (stepData.endTime !== undefined) update.end_time = stepData.endTime ?? null;
  if (stepData.description !== undefined) update.description = stepData.description ?? null;
  if (stepData.transportType !== undefined) update.transport_type = stepData.transportType ?? null;
  if (stepData.referenceNumber !== undefined) update.reference_number = stepData.referenceNumber ?? null;
  if (stepData.departureName !== undefined) update.departure_name = stepData.departureName ?? null;
  if (stepData.arrivalName !== undefined) update.arrival_name = stepData.arrivalName ?? null;
  if (stepData.estimatedDuration !== undefined) update.estimated_duration = stepData.estimatedDuration ?? null;
  if (stepData.restaurantName !== undefined) update.restaurant_name = stepData.restaurantName ?? null;
  if (stepData.cuisineType !== undefined) update.cuisine_type = stepData.cuisineType ?? null;
  if (stepData.budget !== undefined) update.budget = stepData.budget ?? null;
  if (stepData.accommodationName !== undefined) update.accommodation_name = stepData.accommodationName ?? null;
  if (stepData.roomType !== undefined) update.room_type = stepData.roomType ?? null;
  if (stepData.checkInTime !== undefined) update.check_in_time = stepData.checkInTime ?? null;
  if (stepData.checkOutTime !== undefined) update.check_out_time = stepData.checkOutTime ?? null;
  if (stepData.reservationNumber !== undefined) update.reservation_number = stepData.reservationNumber ?? null;
  if (stepData.rating !== undefined) update.rating = stepData.rating ?? null;
  if (stepData.activityType !== undefined) update.activity_type = stepData.activityType ?? null;
  if (stepData.guideName !== undefined) update.guide_name = stepData.guideName ?? null;
  if (stepData.walkingLevel !== undefined) update.walking_level = stepData.walkingLevel ?? null;
  if (stepData.breakPurpose !== undefined) update.break_purpose = stepData.breakPurpose ?? null;
  if (stepData.internalNotes !== undefined) update.internal_notes = stepData.internalNotes ?? null;
  return update;
}
