import { AUTHOR_SOCIAL_KEYS, AuthorSocials } from "@/lib/admin/db";

/**
 * Server-side validation for editable PROFILE data (identity + author + social).
 * Security credentials (password, 2FA, role, status) are NEVER handled here.
 */

const HOST_PATTERNS: Partial<Record<keyof AuthorSocials, RegExp>> = {
  linkedin: /^([\w-]+\.)?linkedin\.com$/i,
  instagram: /^([\w-]+\.)?instagram\.com$/i,
  x: /^([\w-]+\.)?(x\.com|twitter\.com)$/i,
  github: /^([\w-]+\.)?github\.com$/i,
  youtube: /^([\w-]+\.)?(youtube\.com|youtu\.be)$/i,
  // website: any host allowed (validated for scheme only)
};

const LABELS: Record<keyof AuthorSocials, string> = {
  linkedin: "LinkedIn",
  instagram: "Instagram",
  x: "X (Twitter)",
  website: "Website",
  github: "GitHub",
  youtube: "YouTube",
};

/** Returns a cleaned URL, or an error message. Empty input clears the field. */
export function sanitizeSocialUrl(
  key: keyof AuthorSocials,
  value: unknown
): { ok: true; value: string } | { ok: false; error: string } {
  const raw = typeof value === "string" ? value.trim() : "";
  if (!raw) return { ok: true, value: "" };

  let url: URL;
  try {
    url = new URL(raw);
  } catch {
    return { ok: false, error: `Enter a valid ${LABELS[key]} URL (including https://).` };
  }

  // Only http(s) — this rejects javascript:, data:, vbscript:, file:, etc.
  if (url.protocol !== "https:" && url.protocol !== "http:") {
    return { ok: false, error: `${LABELS[key]} link must be an http(s) URL.` };
  }

  const pattern = HOST_PATTERNS[key];
  if (pattern && !pattern.test(url.hostname)) {
    return { ok: false, error: `That doesn't look like a ${LABELS[key]} URL.` };
  }

  return { ok: true, value: url.toString() };
}

export interface CleanProfile {
  displayName?: string;
  jobTitle?: string;
  shortBio?: string;
  longBio?: string;
  location?: string;
  professionalEmail?: string;
  authorSlug?: string;
  avatarMediaId?: string | null;
  avatarUrl?: string | null;
  socials?: AuthorSocials;
}

const MAX = {
  displayName: 80,
  jobTitle: 120,
  shortBio: 280,
  longBio: 4000,
  location: 120,
  professionalEmail: 160,
  authorSlug: 60,
} as const;

function str(v: unknown, max: number): string {
  return (typeof v === "string" ? v : "").trim().slice(0, max);
}

/**
 * Validates and cleans a profile PATCH body. Only known profile fields are
 * accepted; anything else (role, status, passwordHash…) is ignored entirely.
 */
export function validateProfilePatch(
  body: Record<string, unknown>
): { ok: true; data: CleanProfile } | { ok: false; error: string } {
  const data: CleanProfile = {};

  if ("displayName" in body) data.displayName = str(body.displayName, MAX.displayName);
  if ("jobTitle" in body) data.jobTitle = str(body.jobTitle, MAX.jobTitle);
  if ("shortBio" in body) data.shortBio = str(body.shortBio, MAX.shortBio);
  if ("longBio" in body) data.longBio = str(body.longBio, MAX.longBio);
  if ("location" in body) data.location = str(body.location, MAX.location);

  if ("professionalEmail" in body) {
    const email = str(body.professionalEmail, MAX.professionalEmail).toLowerCase();
    if (email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
      return { ok: false, error: "Enter a valid professional email address." };
    }
    data.professionalEmail = email;
  }

  if ("authorSlug" in body) {
    const slug = str(body.authorSlug, MAX.authorSlug)
      .toLowerCase()
      .replace(/[^a-z0-9]+/g, "-")
      .replace(/^-+|-+$/g, "");
    if (slug && !/^[a-z0-9][a-z0-9-]*$/.test(slug)) {
      return { ok: false, error: "Author slug may contain only lowercase letters, numbers and hyphens." };
    }
    data.authorSlug = slug;
  }

  if ("avatarMediaId" in body) {
    data.avatarMediaId = typeof body.avatarMediaId === "string" ? body.avatarMediaId : null;
  }
  if ("avatarUrl" in body) {
    const v = typeof body.avatarUrl === "string" ? body.avatarUrl.trim() : "";
    if (v && !/^\/|^https?:\/\//i.test(v)) {
      return { ok: false, error: "Avatar URL must be a site-relative path or an http(s) URL." };
    }
    data.avatarUrl = v || null;
  }

  if ("socials" in body && body.socials && typeof body.socials === "object") {
    const inSocials = body.socials as Record<string, unknown>;
    const socials: AuthorSocials = {};
    for (const key of AUTHOR_SOCIAL_KEYS) {
      if (key in inSocials) {
        const res = sanitizeSocialUrl(key, inSocials[key]);
        if (!res.ok) return { ok: false, error: res.error };
        socials[key] = res.value;
      }
    }
    data.socials = socials;
  }

  return { ok: true, data };
}
