import getAnimeInfo from "@/src/utils/getAnimeInfo.utils";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faPlay,
faClosedCaptioning,
faMicrophone,
} from "@fortawesome/free-solid-svg-icons";
import { useEffect, useState, useMemo } from "react";
import { Link, useNavigate, useParams } from "react-router-dom";
import CategoryCard from "@/src/components/categorycard/CategoryCard";
import Loader from "@/src/components/Loader/Loader";
import Error from "@/src/components/error/Error";
import { useLanguage } from "@/src/context/LanguageContext";
import Voiceactor from "@/src/components/voiceactor/Voiceactor";
import getSafeTitle from "@/src/utils/getSafetitle";
import { Helmet } from 'react-helmet-async';
import InfoTag from "@/src/components/ui/InfoTag/InfoTag";
import {
generateDescription,
generateKeywords,
generateCanonicalUrl,
generateOGImage,
generateAnimeStructuredData,
generateBreadcrumbStructuredData,
optimizeTitle,
} from '@/src/utils/seo.utils';
const InfoItem = ({ label, value, isProducer = true }) => {
if (!value) return null;
const renderValue = () => {
if (Array.isArray(value)) {
return value.map((item, index) => (
{isProducer ? (
:;,.?/\\|{}[\]`~*_]/g, "").split(" ").join("-").replace(/-+/g, "-")}`}
className="cursor-pointer transition-colors duration-300 hover:text-gray-300"
>
{item}
) : (
item
)}
{index < value.length - 1 && ", "}
));
}
if (isProducer) {
return (
:;,.?/\\|{}[\]`~*_]/g, "").split(" ").join("-").replace(/-+/g, "-")}`}
className="cursor-pointer transition-colors duration-300 hover:text-gray-300"
>
{value}
);
}
return value;
};
return (
{`${label}: `}
{renderValue()}
);
};
const Synopsis = ({ text, isFull, onToggle, isMobile = false }) => {
if (!text) return null;
const limit = isMobile ? 150 : 270;
const isTooLong = text.length > limit;
return (
{isTooLong ? (
<>
{isFull ? text : (isMobile ?
{text}
: `${text.slice(0, limit)}...`)}
>
) : text}
);
};
const TagsList = ({ tags }) => (
{tags.map((tag, index) => tag.condition && (
))}
);
const DetailGrid = ({ info, isMobile = false }) => {
const items = [
{ label: "Japanese", value: info?.Japanese },
{ label: "Synonyms", value: info?.Synonyms },
{ label: "Aired", value: info?.Aired },
{ label: "Premiered", value: info?.Premiered },
{ label: "Duration", value: info?.Duration },
{ label: "Status", value: info?.Status },
{ label: "MAL Score", value: info?.["MAL Score"] },
];
return (
{items.map((item, index) => (
))}
{info?.Genres && (
Genres
{info.Genres.map((genre, index) => (
{genre}
))}
)}
);
};
function AnimeInfo({ random = false }) {
const { language } = useLanguage();
const { id: paramId } = useParams();
const id = random ? null : paramId;
const { id: currentId } = useParams();
const navigate = useNavigate();
const [isFull, setIsFull] = useState(false);
const [animeInfo, setAnimeInfo] = useState(null);
const [seasons, setSeasons] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
if (id === "404-not-found-page") return;
const fetchAnimeInfo = async () => {
setLoading(true);
try {
const data = await getAnimeInfo(id, random);
if (!data?.data) throw new Error("Anime not found");
setSeasons(data?.seasons);
setAnimeInfo(data.data);
} catch (err) {
console.error("Error fetching anime info:", err);
setError(err);
} finally {
setLoading(false);
}
};
fetchAnimeInfo();
window.scrollTo({ top: 0, behavior: "smooth" });
}, [id, random]);
const seoData = useMemo(() => {
if (!animeInfo) return null;
const { title, japanese_title, poster, animeInfo: info } = animeInfo;
const safeTitle = getSafeTitle(title, language, japanese_title);
return {
safeTitle,
title: optimizeTitle(`Watch ${safeTitle} Sub Dub Online Free`),
description: generateDescription(info?.Overview),
keywords: generateKeywords(animeInfo),
canonical: generateCanonicalUrl(`/${animeInfo.id}`),
ogImage: generateOGImage(poster),
structured: generateAnimeStructuredData(animeInfo),
breadcrumb: generateBreadcrumbStructuredData([
{ name: 'Home', url: '/' },
{ name: animeInfo.title, url: `/${animeInfo.id}` }
])
};
}, [animeInfo, language]);
const tags = useMemo(() => {
if (!animeInfo?.animeInfo?.tvInfo) return [];
const info = animeInfo.animeInfo;
return [
{ condition: info.tvInfo.rating, text: info.tvInfo.rating, bgColor: "#ffffff" },
{ condition: info.tvInfo.quality, text: info.tvInfo.quality, bgColor: "#FFBADE" },
{ condition: info.tvInfo.sub, text: info.tvInfo.sub, icon: faClosedCaptioning, bgColor: "#B0E3AF" },
{ condition: info.tvInfo.dub, text: info.tvInfo.dub, icon: faMicrophone, bgColor: "#B9E7FF" },
];
}, [animeInfo]);
if (loading) return ;
if (error || (!animeInfo && !loading)) return ;
if (!animeInfo) {
navigate("/404-not-found-page");
return null;
}
const { poster, japanese_title, animeInfo: info } = animeInfo;
const isAiring = animeInfo?.animeInfo?.Status?.toLowerCase() !== "not-yet-aired";
return (
<>
{seoData.title}
{/* Mobile Layout */}

{animeInfo.adultContent && (
18+
)}
{seoData.safeTitle}
{language === "EN" && japanese_title && (
JP: {japanese_title}
)}
setIsFull(!isFull)} isMobile />
{isAiring ? (
Watch Now
) : (
Not yet released
)}
{/* Desktop Layout */}

{animeInfo.adultContent && (
18+
)}
{seoData.safeTitle}
{language === "EN" && japanese_title && (
JP Title: {japanese_title}
)}
setIsFull(!isFull)} />
{isAiring ? (
Watch Now
) : (
Not yet released
)}
{/* Sections */}
{seasons?.length > 0 && (
More Seasons
{seasons.map((season, index) => (
')`,
backgroundSize: '3px 3px'
}}
/>
))}
)}
{animeInfo?.charactersVoiceActors?.length > 0 && (
)}
{animeInfo?.recommended_data?.length > 0 && (
)}
>
);
}
export default AnimeInfo;