"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import Link from "next/link";
import { useParams, useRouter } from "next/navigation";
import MainTitle from "@/components/layout/dashboard/main-title";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import DataService from "@/config/axios";
import { useRequireSuperAdmin } from "@/hooks/use-require-super-admin";
import { getApiErrorMessage } from "@/lib/api-error";
import { uploadAdminBlogImage } from "@/lib/upload-admin-blog-image";
import { toast } from "sonner";
import { BlogRichTextEditor } from "./blog-rich-text-editor";
import { cn } from "@/lib/utils";

function slugify(value: string) {
  return value
    .toLowerCase()
    .trim()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/(^-|-$)+/g, "");
}

function htmlToPlain(html: string) {
  return html
    .replace(/<[^>]+>/g, " ")
    .replace(/&nbsp;/gi, " ")
    .replace(/\s+/g, " ")
    .trim();
}

type Category = { _id: string; name: string; slug: string; description?: string };
type BlogRow = {
  _id: string;
  title: string;
  slug: string;
  excerpt?: string;
  content: string;
  status: "draft" | "published";
  category?: { _id: string; name: string; slug: string } | null;
  coverImage?: string;
  metaTitle?: string;
  metaDescription?: string;
  tags?: string[];
};

type Props = {
  blogId: string | null;
};

type FieldErrors = {
  title?: string;
  category?: string;
  content?: string;
};

function validateBlogForm(
  form: {
    title: string;
    content: string;
    category: string;
  },
  categoryCount: number,
): FieldErrors {
  const errors: FieldErrors = {};
  if (!form.title.trim()) {
    errors.title = "Title is required.";
  }
  if (categoryCount === 0) {
    errors.category = "Create at least one category before publishing a blog.";
  } else if (!form.category) {
    errors.category = "Please select a category.";
  }
  if (!htmlToPlain(form.content)) {
    errors.content = "Article content is required.";
  }
  return errors;
}

export default function AdminBlogEditorPage({ blogId }: Props) {
  const ready = useRequireSuperAdmin();
  const router = useRouter();
  const params = useParams();
  const app = params.app as string;

  const isEdit = Boolean(blogId);
  const listHref = `/${app}/admin/blogs`;

  const [loading, setLoading] = useState(true);
  const [categories, setCategories] = useState<Category[]>([]);
  const [editSlug, setEditSlug] = useState<string | null>(null);
  const [thumbUploading, setThumbUploading] = useState(false);
  const [saving, setSaving] = useState(false);
  const [fieldErrors, setFieldErrors] = useState<FieldErrors>({});
  const [blogForm, setBlogForm] = useState({
    title: "",
    metaTitle: "",
    metaDescription: "",
    tagsInput: "",
    content: "",
    category: "",
    status: "published" as "draft" | "published",
    coverImage: "",
  });

  const loadCategories = useCallback(async () => {
    const res = await DataService.get("/admin/blog-categories");
    const rows: Category[] = res.data?.data || [];
    setCategories(rows);
    return rows;
  }, []);

  const loadBlog = useCallback(async (id: string) => {
    const res = await DataService.get(`/admin/blogs/${id}`);
    return res.data?.data as BlogRow | undefined;
  }, []);

  useEffect(() => {
    if (!ready) return;
    let cancelled = false;
    (async () => {
      setLoading(true);
      try {
        const cats = await loadCategories();
        if (cancelled) return;
        if (blogId) {
          const b = await loadBlog(blogId);
          if (cancelled) return;
          if (!b) {
            toast.error("Blog not found");
            router.replace(listHref);
            return;
          }
          setEditSlug(b.slug);
          setBlogForm({
            title: b.title,
            metaTitle: b.metaTitle || "",
            metaDescription: b.metaDescription ?? b.excerpt ?? "",
            tagsInput: (b.tags || []).join(", "),
            content: b.content,
            category: b.category?._id || "",
            status: b.status || "published",
            coverImage: b.coverImage || "",
          });
        } else {
          setEditSlug(null);
          setBlogForm({
            title: "",
            metaTitle: "",
            metaDescription: "",
            tagsInput: "",
            content: "",
            category: cats[0]?._id || "",
            status: "published",
            coverImage: "",
          });
        }
      } catch (e: unknown) {
        if (!cancelled) toast.error(getApiErrorMessage(e, "Failed to load"));
      } finally {
        if (!cancelled) setLoading(false);
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [ready, blogId, loadBlog, loadCategories, listHref, router]);

  const slugPreview = useMemo(() => {
    const base = (blogForm.metaTitle || blogForm.title).trim();
    return base ? slugify(base) : "";
  }, [blogForm.metaTitle, blogForm.title]);

  const saveBlog = async () => {
    const errors = validateBlogForm(blogForm, categories.length);
    if (Object.keys(errors).length > 0) {
      setFieldErrors(errors);
      const first = errors.title
        ? "blog-field-title"
        : errors.category
          ? "blog-field-category"
          : errors.content
            ? "blog-field-content"
            : null;
      if (first) {
        requestAnimationFrame(() =>
          document.getElementById(first)?.scrollIntoView({ behavior: "smooth", block: "center" }),
        );
      }
      return;
    }
    setFieldErrors({});

    try {
      setSaving(true);
      const metaDesc = blogForm.metaDescription.trim();
      const tags = blogForm.tagsInput
        .split(",")
        .map((t) => t.trim())
        .filter(Boolean);
      const payload = {
        title: blogForm.title.trim(),
        excerpt: metaDesc,
        metaTitle: blogForm.metaTitle.trim(),
        metaDescription: metaDesc,
        tags,
        content: blogForm.content.trim(),
        category: blogForm.category,
        status: blogForm.status,
        coverImage: blogForm.coverImage.trim(),
      };
      if (isEdit && blogId) {
        await DataService.patch(`/admin/blogs/${blogId}`, payload);
        toast.success("Blog updated");
      } else {
        await DataService.post("/admin/blogs", payload);
        toast.success("Blog created");
      }
      router.push(listHref);
    } catch (e: unknown) {
      toast.error(getApiErrorMessage(e, "Could not save blog"));
    } finally {
      setSaving(false);
    }
  };

  if (!ready || loading) {
    return <div className="rounded-md border bg-white p-8 text-center text-gray-500">Loading…</div>;
  }

  return (
    <div className="space-y-6">
      <MainTitle title={isEdit ? "Edit blog" : "Add blog"} goBack>
        <Button variant="outline" asChild>
          <Link href={listHref}>Back to list</Link>
        </Button>
      </MainTitle>

      <div className="rounded-lg border bg-white p-6 shadow-sm">
        <div className="mx-auto grid max-w-3xl gap-4">
          <div id="blog-field-title" className="grid gap-2">
            <Label htmlFor="blog-title">
              Title <span className="text-destructive">*</span>
            </Label>
            <Input
              id="blog-title"
              aria-invalid={Boolean(fieldErrors.title)}
              aria-describedby={fieldErrors.title ? "blog-title-error" : undefined}
              className={cn(fieldErrors.title && "border-destructive focus-visible:ring-destructive")}
              value={blogForm.title}
              onChange={(e) => {
                setBlogForm((p) => ({ ...p, title: e.target.value }));
                setFieldErrors((p) => ({ ...p, title: undefined }));
              }}
            />
            {fieldErrors.title ? (
              <p id="blog-title-error" className="text-sm text-destructive" role="alert">
                {fieldErrors.title}
              </p>
            ) : null}
          </div>
          <div id="blog-field-category" className="grid gap-2">
            <Label htmlFor="blog-category">
              Article category <span className="text-destructive">*</span>
            </Label>
            <select
              id="blog-category"
              aria-invalid={Boolean(fieldErrors.category)}
              aria-describedby={fieldErrors.category ? "blog-category-error" : undefined}
              className={cn(
                "h-10 w-full rounded-md border border-input bg-background px-3 text-sm",
                fieldErrors.category && "border-destructive",
              )}
              value={blogForm.category}
              onChange={(e) => {
                setBlogForm((p) => ({ ...p, category: e.target.value }));
                setFieldErrors((p) => ({ ...p, category: undefined }));
              }}
            >
              <option value="">Select category</option>
              {categories.map((c) => (
                <option key={c._id} value={c._id}>
                  {c.name}
                </option>
              ))}
            </select>
            {fieldErrors.category ? (
              <p id="blog-category-error" className="text-sm text-destructive" role="alert">
                {fieldErrors.category}
              </p>
            ) : null}
          </div>
          <div className="grid gap-2">
            <Label>Tags</Label>
            <Input
              placeholder="e.g. news, product, guide"
              value={blogForm.tagsInput}
              onChange={(e) => setBlogForm((p) => ({ ...p, tagsInput: e.target.value }))}
            />
            <p className="text-xs text-muted-foreground">Comma-separated</p>
          </div>
          <div className="grid gap-2">
            <Label>Meta title</Label>
            <Input
              value={blogForm.metaTitle}
              onChange={(e) => setBlogForm((p) => ({ ...p, metaTitle: e.target.value }))}
              placeholder="SEO title"
            />
          </div>
          <div className="rounded-md border bg-muted/30 px-3 py-2 text-sm">
            <span className="text-muted-foreground">Slug</span>
            <div className="mt-0.5 font-mono  text-black">
              {isEdit && editSlug ? editSlug : slugPreview || "—"}
            </div>
            {!isEdit ? (
              <p className="mt-1 text-xs text-muted-foreground">
                Generated from meta title (or title if meta title is empty). Saved when you create the post.
              </p>
            ) : (
              <p className="mt-1 text-xs text-muted-foreground">Slug stays the same when editing.</p>
            )}
          </div>
          <div className="grid gap-2">
            <Label>Meta description</Label>
            <Textarea
              value={blogForm.metaDescription}
              onChange={(e) => setBlogForm((p) => ({ ...p, metaDescription: e.target.value }))}
              placeholder="SEO description"
              rows={3}
            />
          </div>
          <div className="grid gap-2">
            <Label>Thumbnail</Label>
            <Input
              type="file"
              accept="image/png,image/jpeg,image/webp,image/gif"
              disabled={thumbUploading}
              onChange={async (e) => {
                const file = e.target.files?.[0];
                if (!file) return;
                setThumbUploading(true);
                try {
                  const url = await uploadAdminBlogImage(file);
                  setBlogForm((p) => ({ ...p, coverImage: url }));
                  toast.success("Thumbnail uploaded");
                } catch (err: unknown) {
                  toast.error(err instanceof Error ? err.message : "Upload failed");
                } finally {
                  setThumbUploading(false);
                  e.target.value = "";
                }
              }}
            />
            {blogForm.coverImage ? (
              /* eslint-disable-next-line @next/next/no-img-element -- admin preview of uploaded URL */
              <img
                src={blogForm.coverImage}
                alt=""
                className="mt-1 max-h-40 rounded-md border object-cover"
              />
            ) : null}
          </div>
          <div id="blog-field-content" className="grid gap-2">
            <Label>
              Article <span className="text-destructive">*</span>
            </Label>
            <div
              className={cn(
                "rounded-md",
                fieldErrors.content && "ring-2 ring-destructive ring-offset-2 ring-offset-background",
              )}
            >
              <BlogRichTextEditor
                value={blogForm.content}
                onChange={(html) => {
                  setBlogForm((p) => ({ ...p, content: html }));
                  setFieldErrors((p) => ({ ...p, content: undefined }));
                }}
              />
            </div>
            {fieldErrors.content ? (
              <p id="blog-content-error" className="text-sm text-destructive" role="alert">
                {fieldErrors.content}
              </p>
            ) : null}
          </div>
          <div className="grid gap-2">
            <Label>Status</Label>
            <select
              className="h-10 w-full rounded-md border border-input bg-background px-3 text-sm"
              value={blogForm.status}
              onChange={(e) =>
                setBlogForm((p) => ({
                  ...p,
                  status: e.target.value === "draft" ? "draft" : "published",
                }))
              }
            >
              <option value="published">Published</option>
              <option value="draft">Draft</option>
            </select>
          </div>

          <div className="flex flex-wrap justify-end gap-2 border-t pt-6">
            <Button variant="outline" asChild>
              <Link href={listHref}>Cancel</Link>
            </Button>
            <Button onClick={saveBlog} disabled={thumbUploading || saving}>
              {saving ? "Saving…" : "Save"}
            </Button>
          </div>
        </div>
      </div>
    </div>
  );
}
