import { db } from "@/db";
import { instagramCache } from "@/db/schema";
import { eq, sql } from "drizzle-orm";

export const INSTAGRAM_HANDLE = "floriangrossdesign";
export const INSTAGRAM_PROFILE_URL = "https://www.instagram.com/floriangrossdesign/";
export const MAX_POSTS = 4;
const CACHE_KEY = "instagram:latest";
const CACHE_TTL_MS = 1000 * 60 * 60 * 6; // 6 hours

export type InstagramPost = {
  id: string;
  permalink: string;
  imageUrl: string;
  caption: string;
  likes: number | null;
  comments: number | null;
  timestamp: string | null;
  mediaType: string;
};

export type InstagramPayload = {
  handle: string;
  profileUrl: string;
  followers: number | null;
  posts: InstagramPost[];
  source: "graph-api" | "web-profile" | "cache" | "fallback";
  fetchedAt: string;
  live: boolean;
};

const GRAPH_ENDPOINTS = [
  "https://graph.instagram.com/me/media",
  "https://graph.instagram.com/v21.0/me/media",
];

const WEB_PROFILE_ENDPOINTS = [
  (u: string) => `https://www.instagram.com/api/v1/users/web_profile_info/?username=${u}`,
  (u: string) => `https://i.instagram.com/api/v1/users/web_profile_info/?username=${u}`,
];

const IG_APP_IDS = ["936619743392459", "124024574287414"];

const BROWSER_UA =
  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36";

async function fetchJson(url: string, init?: RequestInit, timeoutMs = 4500) {
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), timeoutMs);
  try {
    const res = await fetch(url, {
      ...init,
      signal: controller.signal,
      cache: "no-store",
      headers: {
        "User-Agent": BROWSER_UA,
        "Accept-Language": "en-US,en;q=0.9",
        ...(init?.headers ?? {}),
      },
    });
    if (!res.ok) return null;
    const text = await res.text();
    try {
      return JSON.parse(text) as unknown;
    } catch {
      return null;
    }
  } catch {
    return null;
  } finally {
    clearTimeout(timer);
  }
}

function clip(value: string, max = 180) {
  const clean = value.replace(/\s+/g, " ").trim();
  return clean.length > max ? `${clean.slice(0, max - 1).trimEnd()}…` : clean;
}

/* ------------------------------------------------------------------ */
/* Strategy 1 – official Instagram Graph API (needs a token)           */
/* ------------------------------------------------------------------ */

async function fromGraphApi(): Promise<InstagramPayload | null> {
  const token = process.env.INSTAGRAM_ACCESS_TOKEN;
  if (!token) return null;

  for (const endpoint of GRAPH_ENDPOINTS) {
    const fields =
      "id,caption,media_type,media_url,thumbnail_url,permalink,timestamp,like_count,comments_count";
    const data = (await fetchJson(
      `${endpoint}?fields=${encodeURIComponent(fields)}&limit=${MAX_POSTS}&access_token=${token}`,
    )) as { data?: Record<string, unknown>[] } | null;
    if (!data?.data?.length) continue;

    const posts: InstagramPost[] = data.data.slice(0, MAX_POSTS).map((raw) => ({
      id: String(raw.id ?? ""),
      permalink: String(raw.permalink ?? INSTAGRAM_PROFILE_URL),
      imageUrl: String(raw.media_url ?? raw.thumbnail_url ?? ""),
      caption: clip(String(raw.caption ?? "")),
      likes: typeof raw.like_count === "number" ? raw.like_count : null,
      comments: typeof raw.comments_count === "number" ? raw.comments_count : null,
      timestamp: raw.timestamp ? String(raw.timestamp) : null,
      mediaType: String(raw.media_type ?? "IMAGE"),
    }));

    if (!posts.length) continue;
    return {
      handle: `@${INSTAGRAM_HANDLE}`,
      profileUrl: INSTAGRAM_PROFILE_URL,
      followers: null,
      posts,
      source: "graph-api",
      fetchedAt: new Date().toISOString(),
      live: true,
    };
  }
  return null;
}

/* ------------------------------------------------------------------ */
/* Strategy 2 – public web profile endpoint                            */
/* ------------------------------------------------------------------ */

type WebProfileResponse = {
  data?: {
    user?: {
      edge_followed_by?: { count?: number };
      edge_owner_to_timeline_media?: {
        edges?: {
          node?: {
            id?: string;
            shortcode?: string;
            edge_media_to_caption?: { edges?: { node?: { text?: string } }[] };
            thumbnail_src?: string;
            display_url?: string;
            edge_liked_by?: { count?: number };
            edge_media_preview_like?: { count?: number };
            edge_media_to_comment?: { count?: number };
            taken_at_timestamp?: number;
            __typename?: string;
          };
        }[];
      };
    };
  };
};

async function fromWebProfile(): Promise<InstagramPayload | null> {
  for (const build of WEB_PROFILE_ENDPOINTS) {
    for (const appId of IG_APP_IDS) {
      const data = (await fetchJson(build(INSTAGRAM_HANDLE), {
        headers: {
          "x-ig-app-id": appId,
          Accept: "*/*",
          Referer: INSTAGRAM_PROFILE_URL,
          "Sec-Fetch-Site": "same-origin",
        },
      })) as WebProfileResponse | null;

      const user = data?.data?.user;
      const edges = user?.edge_owner_to_timeline_media?.edges ?? [];
      if (!edges.length) continue;

      const posts: InstagramPost[] = edges
        .slice(0, MAX_POSTS)
        .map((edge) => {
          const node = edge?.node ?? {};
          const shortcode = node.shortcode;
          return {
            id: String(node.id ?? shortcode ?? Math.random()),
            permalink: shortcode
              ? `https://www.instagram.com/p/${shortcode}/`
              : INSTAGRAM_PROFILE_URL,
            imageUrl: node.thumbnail_src ?? node.display_url ?? "",
            caption: clip(node.edge_media_to_caption?.edges?.[0]?.node?.text ?? ""),
            likes:
              node.edge_liked_by?.count ?? node.edge_media_preview_like?.count ?? null,
            comments: node.edge_media_to_comment?.count ?? null,
            timestamp: node.taken_at_timestamp
              ? new Date(node.taken_at_timestamp * 1000).toISOString()
              : null,
            mediaType: node.__typename?.replace("Graph", "").toUpperCase() ?? "IMAGE",
          };
        })
        .filter((p) => p.imageUrl);

      if (!posts.length) continue;
      return {
        handle: `@${INSTAGRAM_HANDLE}`,
        profileUrl: INSTAGRAM_PROFILE_URL,
        followers: user?.edge_followed_by?.count ?? null,
        posts,
        source: "web-profile",
        fetchedAt: new Date().toISOString(),
        live: true,
      };
    }
  }
  return null;
}

/* ------------------------------------------------------------------ */
/* Cache helpers                                                       */
/* ------------------------------------------------------------------ */

async function readCache(): Promise<InstagramPayload | null> {
  try {
    const rows = await db
      .select()
      .from(instagramCache)
      .where(eq(instagramCache.key, CACHE_KEY))
      .limit(1);
    const row = rows[0];
    if (!row) return null;
    return row.payload as InstagramPayload;
  } catch {
    return null;
  }
}

async function writeCache(payload: InstagramPayload) {
  try {
    await db.execute(sql`
      CREATE TABLE IF NOT EXISTS instagram_cache (
        key varchar(64) PRIMARY KEY,
        payload jsonb NOT NULL,
        source varchar(64) NOT NULL,
        fetched_at timestamptz NOT NULL DEFAULT now()
      )`);
    await db
      .insert(instagramCache)
      .values({ key: CACHE_KEY, payload, source: payload.source })
      .onConflictDoUpdate({
        target: instagramCache.key,
        set: { payload, source: payload.source, fetchedAt: new Date() },
      });
  } catch {
    /* cache is best-effort */
  }
}

/* ------------------------------------------------------------------ */
/* Fallback – the studio's own latest work, always available           */
/* ------------------------------------------------------------------ */

type FallbackItem = { id: string; imageUrl: string; caption: string; href: string };

export function buildFallback(items: FallbackItem[]): InstagramPayload {
  return {
    handle: `@${INSTAGRAM_HANDLE}`,
    profileUrl: INSTAGRAM_PROFILE_URL,
    followers: null,
    posts: items.slice(0, MAX_POSTS).map((item) => ({
      id: `fb-${item.id}`,
      permalink: item.href,
      imageUrl: item.imageUrl,
      caption: clip(item.caption),
      likes: null,
      comments: null,
      timestamp: null,
      mediaType: "IMAGE",
    })),
    source: "fallback",
    fetchedAt: new Date().toISOString(),
    live: false,
  };
}

/* ------------------------------------------------------------------ */
/* Public entry point                                                  */
/* ------------------------------------------------------------------ */

export async function getInstagramFeed(
  fallbackItems: FallbackItem[],
): Promise<InstagramPayload> {
  // 1. Fresh cache?
  const cached = await readCache();
  if (cached?.posts?.length) {
    const age = Date.now() - new Date(cached.fetchedAt).getTime();
    if (age < CACHE_TTL_MS && cached.live) return cached;
  }

  // 2. Try live sources.
  const live = (await fromGraphApi()) ?? (await fromWebProfile());
  if (live) {
    await writeCache(live);
    return live;
  }

  // 3. Stale live cache is better than nothing.
  if (cached?.posts?.length && cached.live) return cached;

  // 4. Deterministic fallback.
  return buildFallback(fallbackItems);
}
