import { promises as fs } from "fs";
import path from "path";
import type { GeneratedPost, GeneratedPostStatus } from "@/types/workflow";
import { isMariaDbEnabled } from "@/lib/db/config";
import {
  getGeneratedPostFromDb,
  getNextVersionForSequenceFromDb,
  listGeneratedPostsFromDb,
  saveGeneratedPostToDb,
  updateGeneratedPostFields,
} from "@/lib/db/repositories/generated-posts-repo";

const DATA_DIR = path.join(process.cwd(), "data");
const POSTS_FILE = path.join(DATA_DIR, "generated-posts.json");

async function ensureStore() {
  await fs.mkdir(DATA_DIR, { recursive: true });
  try {
    await fs.access(POSTS_FILE);
  } catch {
    await fs.writeFile(POSTS_FILE, "[]", "utf-8");
  }
}

async function readAll(): Promise<GeneratedPost[]> {
  await ensureStore();
  const raw = await fs.readFile(POSTS_FILE, "utf-8");
  const posts = JSON.parse(raw) as GeneratedPost[];
  return posts.map(normalizePost);
}

function normalizePost(post: GeneratedPost): GeneratedPost {
  return {
    ...post,
    version: post.version ?? 1,
    parentPostId: post.parentPostId ?? null,
    imageApproved: post.imageApproved ?? false,
    imageProvider: post.imageProvider ?? undefined,
    imageProviderChain: post.imageProviderChain ?? undefined,
    imageWarning: post.imageWarning ?? null,
    qualityReport: post.qualityReport ?? null,
    mediaAssetId: post.mediaAssetId ?? undefined,
    bannerLayoutId: post.bannerLayoutId ?? undefined,
    regenerationCount: post.regenerationCount ?? 0,
  };
}

async function writeAll(posts: GeneratedPost[]) {
  await ensureStore();
  await fs.writeFile(POSTS_FILE, JSON.stringify(posts, null, 2), "utf-8");
}

export async function listGeneratedPosts(
  projectId?: string,
  projectName?: string,
  userId?: string,
): Promise<GeneratedPost[]> {
  if (isMariaDbEnabled()) {
    try {
      const posts = await listGeneratedPostsFromDb({ projectId, projectName, userId });
      return posts.map(normalizePost);
    } catch (err) {
      console.error("[PostSync] MariaDB listGeneratedPosts failed — JSON fallback:", err);
    }
  }

  const posts = await readAll();
  const filtered = posts.filter((p) => {
    if (userId && p.userId && p.userId !== userId) return false;
    if (projectId) {
      return (
        p.projectId === projectId ||
        (!p.projectId && projectName && p.projectName === projectName)
      );
    }
    if (projectName) return p.projectName === projectName;
    return true;
  });
  return filtered.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
}

export async function getGeneratedPost(id: string): Promise<GeneratedPost | null> {
  if (isMariaDbEnabled()) {
    try {
      const post = await getGeneratedPostFromDb(id);
      return post ? normalizePost(post) : null;
    } catch (err) {
      console.error("[PostSync] MariaDB getGeneratedPost failed — JSON fallback:", err);
    }
  }
  const posts = await readAll();
  return posts.find((p) => p.id === id) ?? null;
}

export async function saveGeneratedPost(post: GeneratedPost): Promise<GeneratedPost> {
  const normalized = normalizePost(post);
  if (isMariaDbEnabled()) {
    try {
      const saved = normalizePost(await saveGeneratedPostToDb(normalized));
      // Mirror JSON so rollback / offline tools can still read recent posts.
      try {
        const posts = await readAll();
        const idx = posts.findIndex((p) => p.id === saved.id);
        if (idx === -1) posts.unshift(saved);
        else posts[idx] = saved;
        await writeAll(posts);
      } catch {
        // ignore mirror
      }
      return saved;
    } catch (err) {
      console.error("[PostSync] MariaDB saveGeneratedPost failed — JSON fallback:", err);
    }
  }
  const posts = await readAll();
  const idx = posts.findIndex((p) => p.id === normalized.id);
  if (idx === -1) {
    posts.unshift(normalized);
  } else {
    posts[idx] = {
      ...posts[idx],
      ...normalized,
      createdAt: posts[idx].createdAt || normalized.createdAt,
    };
  }
  await writeAll(posts);
  return posts[idx === -1 ? 0 : idx]!;
}

export async function updateGeneratedPostStatus(
  id: string,
  status: GeneratedPostStatus,
): Promise<GeneratedPost | null> {
  if (isMariaDbEnabled()) {
    try {
      return await updateGeneratedPostFields(id, {
        status,
        publishedAt: status === "published" ? new Date().toISOString() : undefined,
      });
    } catch (err) {
      console.error("[PostSync] MariaDB updateGeneratedPostStatus failed — JSON fallback:", err);
    }
  }

  const posts = await readAll();
  const index = posts.findIndex((p) => p.id === id);
  if (index === -1) return null;

  posts[index] = {
    ...posts[index],
    status,
    publishedAt: status === "published" ? new Date().toISOString() : posts[index].publishedAt,
  };
  await writeAll(posts);
  return posts[index];
}

export async function updateGeneratedPostPublished(
  id: string,
  platformPermalinks: Record<string, string>,
): Promise<GeneratedPost | null> {
  if (isMariaDbEnabled()) {
    try {
      return await updateGeneratedPostFields(id, {
        status: "published",
        publishedAt: new Date().toISOString(),
        platformPermalinks,
      });
    } catch (err) {
      console.error("[PostSync] MariaDB updateGeneratedPostPublished failed — JSON fallback:", err);
    }
  }

  const posts = await readAll();
  const index = posts.findIndex((p) => p.id === id);
  if (index === -1) return null;

  posts[index] = {
    ...posts[index],
    status: "published",
    publishedAt: new Date().toISOString(),
    platformPermalinks,
  };
  await writeAll(posts);
  return posts[index];
}

export async function updateGeneratedPostCaption(
  id: string,
  caption: string,
): Promise<GeneratedPost | null> {
  if (isMariaDbEnabled()) {
    try {
      return await updateGeneratedPostFields(id, { caption, status: "draft" });
    } catch (err) {
      console.error("[PostSync] MariaDB updateGeneratedPostCaption failed — JSON fallback:", err);
    }
  }

  const posts = await readAll();
  const index = posts.findIndex((p) => p.id === id);
  if (index === -1) return null;

  posts[index] = { ...posts[index], caption, status: "draft" };
  await writeAll(posts);
  return posts[index];
}

export async function updateGeneratedPostImageApproval(
  id: string,
  imageApproved: boolean,
): Promise<GeneratedPost | null> {
  if (isMariaDbEnabled()) {
    try {
      return await updateGeneratedPostFields(id, { imageApproved });
    } catch (err) {
      console.error(
        "[PostSync] MariaDB updateGeneratedPostImageApproval failed — JSON fallback:",
        err,
      );
    }
  }

  const posts = await readAll();
  const index = posts.findIndex((p) => p.id === id);
  if (index === -1) return null;

  posts[index] = { ...posts[index], imageApproved };
  await writeAll(posts);
  return posts[index];
}

export async function getNextVersionForSequence(
  projectId: string,
  sequencePostId: string,
  parentPostId?: string | null,
): Promise<number> {
  if (isMariaDbEnabled()) {
    try {
      return await getNextVersionForSequenceFromDb(projectId, sequencePostId, parentPostId);
    } catch (err) {
      console.error("[PostSync] MariaDB getNextVersionForSequence failed — JSON fallback:", err);
    }
  }

  const posts = await readAll();
  const related = posts.filter((p) => {
    if (p.projectId !== projectId) return false;
    if (parentPostId) {
      return p.id === parentPostId || p.parentPostId === parentPostId;
    }
    return p.sequencePostId === sequencePostId;
  });
  if (!related.length) return 1;
  return Math.max(...related.map((p) => p.version ?? 1)) + 1;
}

/** Draft or approved posts are queued for the next schedule slot — no manual approval required. */
export function isPostQueuedForSchedule(post: GeneratedPost): boolean {
  if (post.status === "published" || post.status === "rejected") return false;
  if (!post.caption?.trim()) return false;
  if (post.status === "draft" || post.status === "approved") return true;
  return false;
}

export async function listQueuedPostsForPublish(
  projectId: string,
  projectName?: string,
): Promise<GeneratedPost[]> {
  const posts = await listGeneratedPosts(projectId, projectName);
  return posts
    .filter(isPostQueuedForSchedule)
    .sort((a, b) => a.createdAt.localeCompare(b.createdAt));
}

export async function getNextQueuedPostForPublish(
  projectId: string,
  projectName?: string,
): Promise<GeneratedPost | null> {
  const queued = await listQueuedPostsForPublish(projectId, projectName);
  return queued[0] ?? null;
}
