import "server-only";

import { createHash } from "crypto";
import type { ResultSetHeader, RowDataPacket } from "mysql2/promise";
import sanitizeHtml from "sanitize-html";
import { renderExternalBlogHtml } from "@/lib/blogger-syndication";
import { getDbPool } from "@/lib/db";
import {
  ensureMarketingBlogSchema,
  getMarketingBlogPostById,
  type MarketingBlogPost,
} from "@/lib/marketing-blog";

declare global {
  var __wordpressSyndicationSchemaPromise: Promise<void> | undefined;
}

const WORDPRESS_API_BASE_URL = "https://public-api.wordpress.com/rest/v1.1";
const DEFAULT_WORDPRESS_SITE = "officialmailkr.wordpress.com";
const DEFAULT_WORDPRESS_BLOG_URL = "https://officialmailkr.wordpress.com";
const DEFAULT_SOURCE_SITE_URL = "https://officialsite.kr";

type WordPressApiPost = {
  ID?: unknown;
  URL?: unknown;
  error?: unknown;
  message?: unknown;
  status?: unknown;
};

type WordPressApiSite = {
  ID?: unknown;
  URL?: unknown;
  name?: unknown;
};

type WordPressSyndicationRow = RowDataPacket & {
  external_post_id: string;
  external_url: string | null;
  last_error: string | null;
  platform_status: "draft" | "failed" | "published";
  post_id: number;
  source_fingerprint: string;
  synced_at: Date | null;
  updated_at: Date;
};

export type WordPressPostStatus = {
  editUrl: string;
  externalPostId: string;
  externalUrl: string | null;
  lastError: string | null;
  postId: number;
  sourceChanged: boolean;
  status: "draft" | "failed" | "published";
  syncedAt: string | null;
};

export type WordPressIntegrationStatus = {
  blogName: string;
  blogUrl: string | null;
  configured: boolean;
  connected: boolean;
  post: WordPressPostStatus | null;
  site: string | null;
};

function getWordPressConfig() {
  const accessToken = process.env.WORDPRESS_ACCESS_TOKEN?.trim();
  const site = process.env.WORDPRESS_SITE?.trim() || DEFAULT_WORDPRESS_SITE;
  const blogUrl = (
    process.env.WORDPRESS_BLOG_URL?.trim() || DEFAULT_WORDPRESS_BLOG_URL
  ).replace(/\/$/, "");
  const sourceSiteUrl = (
    process.env.WORDPRESS_SOURCE_SITE_URL?.trim() || DEFAULT_SOURCE_SITE_URL
  ).replace(/\/$/, "");

  if (!accessToken || !site || !blogUrl) {
    return null;
  }

  return { accessToken, blogUrl, site, sourceSiteUrl };
}

async function ensureWordPressSyndicationSchema() {
  if (!global.__wordpressSyndicationSchemaPromise) {
    global.__wordpressSyndicationSchemaPromise = (async () => {
      await ensureMarketingBlogSchema();
      await getDbPool().query(`
        CREATE TABLE IF NOT EXISTS marketing_blog_syndications (
          id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
          post_id BIGINT UNSIGNED NOT NULL,
          platform VARCHAR(32) NOT NULL,
          external_post_id VARCHAR(128) NOT NULL,
          external_url VARCHAR(768) NULL,
          platform_status ENUM('draft', 'published', 'failed') NOT NULL DEFAULT 'draft',
          source_fingerprint CHAR(64) NOT NULL,
          last_error TEXT NULL,
          synced_at DATETIME NULL,
          created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
          updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
          PRIMARY KEY (id),
          UNIQUE KEY uq_marketing_blog_syndications_post_platform (post_id, platform),
          UNIQUE KEY uq_marketing_blog_syndications_external (platform, external_post_id),
          KEY idx_marketing_blog_syndications_status (platform, platform_status, updated_at),
          CONSTRAINT fk_marketing_blog_syndications_post
            FOREIGN KEY (post_id) REFERENCES marketing_blog_posts(id) ON DELETE CASCADE
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
      `);
    })().catch((error) => {
      global.__wordpressSyndicationSchemaPromise = undefined;
      throw error;
    });
  }

  await global.__wordpressSyndicationSchemaPromise;
}

function escapeHtml(value: string) {
  return value
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#039;");
}

function sourceFingerprint(post: MarketingBlogPost) {
  return createHash("sha256")
    .update([post.title, post.contentMarkdown, post.updatedAt].join("\n"))
    .digest("hex");
}

function wordpressPayload(post: MarketingBlogPost, sourceSiteUrl: string) {
  const sourceUrl = `${sourceSiteUrl}/blog/${post.slug}`;
  const renderedContent = renderExternalBlogHtml(post.contentMarkdown, sourceSiteUrl);
  const intro = post.excerpt
    ? `<p style="margin:0 0 24px;color:#33445f;font-size:17px;line-height:1.9"><strong>${escapeHtml(post.excerpt)}</strong></p>`
    : "";
  const sourceLink = [
    '<section style="margin-top:36px;border-top:1px solid #e5ebf4;padding-top:22px">',
    '<p style="margin:0 0 12px;color:#7183a1;font-size:13px;line-height:1.7">오피셜메일 공식 가이드의 내용을 WordPress 독자에게 맞춰 다시 정리했습니다.</p>',
    `<a href="${escapeHtml(sourceUrl)}" style="display:inline-block;border-radius:9px;background:#2f6df6;color:#fff;padding:12px 18px;text-decoration:none;font-weight:700">오피셜메일 원문에서 계속 읽기</a>`,
    "</section>",
  ].join("");
  const content = sanitizeHtml(`${intro}${renderedContent}${sourceLink}`, {
    allowedTags: sanitizeHtml.defaults.allowedTags.concat(["figure", "figcaption", "img", "details", "summary"]),
    allowedAttributes: {
      ...sanitizeHtml.defaults.allowedAttributes,
      "*": ["style"],
      a: ["href", "style", "target", "rel"],
      img: ["src", "alt", "style"],
    },
    allowedSchemes: ["http", "https", "mailto"],
  });

  return {
    categories: "오피셜메일 가이드",
    content,
    excerpt: post.excerpt,
    publicize: "false",
    slug: post.slug,
    status: "draft" as "draft" | "publish",
    tags: Array.from(new Set(["오피셜메일", ...post.keywords])).slice(0, 12).join(","),
    title: post.title,
  };
}

async function wordpressRequest<T>(
  accessToken: string,
  path: string,
  init?: RequestInit,
) {
  const response = await fetch(`${WORDPRESS_API_BASE_URL}${path}`, {
    ...init,
    headers: {
      authorization: `Bearer ${accessToken}`,
      ...(init?.body ? { "content-type": "application/x-www-form-urlencoded;charset=UTF-8" } : {}),
      ...init?.headers,
    },
    cache: "no-store",
  });
  const payload = await response.json().catch(() => ({})) as T & WordPressApiPost;

  if (!response.ok) {
    const message = typeof payload.message === "string"
      ? payload.message
      : typeof payload.error === "string"
        ? payload.error
        : "WordPress.com API 요청에 실패했습니다.";
    throw new Error(message);
  }

  return payload;
}

function toFormBody(input: Record<string, string>) {
  const body = new URLSearchParams();

  for (const [key, value] of Object.entries(input)) {
    body.set(key, value);
  }

  return body;
}

async function getSyndication(postId: number) {
  await ensureWordPressSyndicationSchema();
  const [rows] = await getDbPool().query<WordPressSyndicationRow[]>(
    `
      SELECT
        post_id,
        external_post_id,
        external_url,
        platform_status,
        source_fingerprint,
        last_error,
        synced_at,
        updated_at
      FROM marketing_blog_syndications
      WHERE post_id = ? AND platform = 'wordpress'
      LIMIT 1
    `,
    [postId],
  );

  return rows[0] ?? null;
}

function mapPostStatus(
  row: WordPressSyndicationRow,
  post: MarketingBlogPost,
  site: string,
): WordPressPostStatus {
  return {
    editUrl: `https://wordpress.com/post/${encodeURIComponent(site)}/${encodeURIComponent(row.external_post_id)}`,
    externalPostId: row.external_post_id,
    externalUrl: row.external_url,
    lastError: row.last_error,
    postId: Number(row.post_id),
    sourceChanged: row.source_fingerprint !== sourceFingerprint(post),
    status: row.platform_status,
    syncedAt: row.synced_at?.toISOString() ?? row.updated_at.toISOString(),
  };
}

async function saveSyndication(input: {
  externalPostId: string;
  externalUrl: string | null;
  fingerprint: string;
  postId: number;
  status: "draft" | "published";
}) {
  await ensureWordPressSyndicationSchema();
  await getDbPool().query<ResultSetHeader>(
    `
      INSERT INTO marketing_blog_syndications (
        post_id,
        platform,
        external_post_id,
        external_url,
        platform_status,
        source_fingerprint,
        last_error,
        synced_at
      ) VALUES (?, 'wordpress', ?, ?, ?, ?, NULL, NOW())
      ON DUPLICATE KEY UPDATE
        external_post_id = VALUES(external_post_id),
        external_url = VALUES(external_url),
        platform_status = VALUES(platform_status),
        source_fingerprint = VALUES(source_fingerprint),
        last_error = NULL,
        synced_at = NOW(),
        updated_at = NOW()
    `,
    [input.postId, input.externalPostId, input.externalUrl, input.status, input.fingerprint],
  );
}

async function markSyndicationFailed(postId: number, message: string) {
  await ensureWordPressSyndicationSchema();
  await getDbPool().query(
    `
      UPDATE marketing_blog_syndications
      SET platform_status = 'failed', last_error = ?, updated_at = NOW()
      WHERE post_id = ? AND platform = 'wordpress'
    `,
    [message.slice(0, 2000), postId],
  );
}

async function requireWordPressConfig() {
  const config = getWordPressConfig();

  if (!config) {
    throw new Error("wordpress-not-configured");
  }

  return config;
}

export async function getWordPressIntegrationStatus(
  postId?: number | null,
): Promise<WordPressIntegrationStatus> {
  const config = getWordPressConfig();

  if (!config) {
    return {
      blogName: "오피셜메일 WordPress",
      blogUrl: null,
      configured: false,
      connected: false,
      post: null,
      site: null,
    };
  }

  let siteInfo: WordPressApiSite | null = null;
  let postStatus: WordPressPostStatus | null = null;

  try {
    siteInfo = await wordpressRequest<WordPressApiSite>(
      config.accessToken,
      `/sites/${encodeURIComponent(config.site)}`,
    );
  } catch {
    return {
      blogName: "오피셜메일 WordPress",
      blogUrl: config.blogUrl,
      configured: true,
      connected: false,
      post: null,
      site: config.site,
    };
  }

  if (postId) {
    const [post, syndication] = await Promise.all([
      getMarketingBlogPostById(postId),
      getSyndication(postId),
    ]);

    if (post && syndication) {
      postStatus = mapPostStatus(syndication, post, config.site);
    }
  }

  return {
    blogName: typeof siteInfo.name === "string" ? siteInfo.name : "오피셜메일 WordPress",
    blogUrl: typeof siteInfo.URL === "string" ? siteInfo.URL.replace(/\/$/, "") : config.blogUrl,
    configured: true,
    connected: true,
    post: postStatus,
    site: config.site,
  };
}

export async function syncWordPressDraft(postId: number) {
  const post = await getMarketingBlogPostById(postId);

  if (!post || post.status !== "published") {
    throw new Error("wordpress-source-not-published");
  }

  const config = await requireWordPressConfig();
  const existing = await getSyndication(postId);
  const payload = wordpressPayload(post, config.sourceSiteUrl);
  if (existing?.platform_status === "published") {
    payload.status = "publish";
  }
  const body = toFormBody(payload);

  try {
    const result = existing
      ? await wordpressRequest<WordPressApiPost>(
        config.accessToken,
        `/sites/${encodeURIComponent(config.site)}/posts/${encodeURIComponent(existing.external_post_id)}`,
        { method: "POST", body },
      )
      : await wordpressRequest<WordPressApiPost>(
        config.accessToken,
        `/sites/${encodeURIComponent(config.site)}/posts/new`,
        { method: "POST", body },
      );
    const externalPostId = String(result.ID ?? existing?.external_post_id ?? "");

    if (!externalPostId) {
      throw new Error("WordPress.com이 게시물 ID를 반환하지 않았습니다.");
    }

    const status = result.status === "publish" || existing?.platform_status === "published"
      ? "published"
      : "draft";
    await saveSyndication({
      externalPostId,
      externalUrl: typeof result.URL === "string" ? result.URL : existing?.external_url ?? null,
      fingerprint: sourceFingerprint(post),
      postId,
      status,
    });

    return getWordPressIntegrationStatus(postId);
  } catch (error) {
    await markSyndicationFailed(
      postId,
      error instanceof Error ? error.message : "WordPress.com 동기화에 실패했습니다.",
    );
    throw error;
  }
}

export async function publishWordPressPost(postId: number) {
  let status = await getWordPressIntegrationStatus(postId);

  if (!status.post || status.post.sourceChanged || status.post.status === "failed") {
    status = await syncWordPressDraft(postId);
  }

  if (!status.post) {
    throw new Error("wordpress-draft-not-found");
  }

  if (status.post.status === "published") {
    return status;
  }

  const config = await requireWordPressConfig();
  const post = await getMarketingBlogPostById(postId);

  if (!post) {
    throw new Error("wordpress-source-not-published");
  }

  const result = await wordpressRequest<WordPressApiPost>(
    config.accessToken,
    `/sites/${encodeURIComponent(config.site)}/posts/${encodeURIComponent(status.post.externalPostId)}`,
    { method: "POST", body: toFormBody({ status: "publish" }) },
  );
  await saveSyndication({
    externalPostId: status.post.externalPostId,
    externalUrl: typeof result.URL === "string" ? result.URL : status.post.externalUrl,
    fingerprint: sourceFingerprint(post),
    postId,
    status: "published",
  });

  return getWordPressIntegrationStatus(postId);
}
