// components/UploadArticle.tsx

'use client'

import { useState } from 'react'
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
import { Button } from "@/components/ui/button"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
import { useToast } from "@/components/ui/use-toast"
import { ToastAction } from "@/components/ui/toast"

export default function UploadArticle() {
  const [formData, setFormData] = useState({
    title: '',
    content: '',
    author: '',
  })
  const [image, setImage] = useState<File | null>(null)
  const [status, setStatus] = useState<{ type: string; message: string } | null>(null)
  const [isUploading, setIsUploading] = useState(false)
  const { toast } = useToast()

  const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
    setFormData({ ...formData, [e.target.name]: e.target.value })
  }

  const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (e.target.files && e.target.files[0]) {
      setImage(e.target.files[0])
    }
  }

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault()
    setIsUploading(true)
    setStatus(null)

    const data = new FormData()
    data.append('title', formData.title)
    data.append('content', formData.content)
    data.append('author', formData.author)
    if (image) {
      data.append('headingImage', image)
    }

    try {
      const token = localStorage.getItem('adminToken')
      if (!token) throw new Error('Unauthorized')

      const res = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/admin/articles`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${token}`,
        },
        body: data,
      })

      if (!res.ok) {
        const errorData = await res.json()
        throw new Error(errorData.error || 'Something went wrong')
      }

      const result = await res.json()
      setStatus({ type: 'success', message: 'Article uploaded successfully!' })
      setFormData({ title: '', content: '', author: '' })
      setImage(null)
      toast({
        title: "Success",
        description: "Article uploaded successfully!",
        action: <ToastAction altText="Okay">Okay</ToastAction>,
      })
    } catch (error: any) {
      console.error('Error uploading article:', error)
      setStatus({ type: 'error', message: error.message || 'Failed to upload article' })
      toast({
        variant: "destructive",
        title: "Error",
        description: error.message || 'Failed to upload article',
        action: <ToastAction altText="Try again">Try again</ToastAction>,
      })
    } finally {
      setIsUploading(false)
    }
  }

  return (
    <Card>
      <CardHeader>
        <CardTitle>Upload New Article</CardTitle>
      </CardHeader>
      <CardContent>
        {status && (
          <Alert variant={status.type === 'error' ? 'destructive' : 'success'}>
            <AlertTitle>{status.type === 'error' ? 'Error' : 'Success'}</AlertTitle>
            <AlertDescription>{status.message}</AlertDescription>
          </Alert>
        )}

        <form onSubmit={handleSubmit} className="space-y-4 mt-4">
          <div>
            <label className="block text-sm font-medium text-gray-700">Title</label>
            <Input
              type="text"
              name="title"
              value={formData.title}
              onChange={handleChange}
              required
              placeholder="Enter article title"
            />
          </div>

          <div>
            <label className="block text-sm font-medium text-gray-700">Content</label>
            <Textarea
              name="content"
              value={formData.content}
              onChange={handleChange}
              required
              placeholder="Enter article content"
              rows={5}
            />
          </div>

          <div>
            <label className="block text-sm font-medium text-gray-700">Author</label>
            <Input
              type="text"
              name="author"
              value={formData.author}
              onChange={handleChange}
              required
              placeholder="Author name"
            />
          </div>

          <div>
            <label className="block text-sm font-medium text-gray-700">Heading Image</label>
            <input
              type="file"
              name="headingImage"
              accept="image/*"
              onChange={handleImageChange}
              className="mt-1 block w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 cursor-pointer focus:outline-none"
              required
            />
            {image && <p className="text-sm text-gray-500 mt-1">{image.name}</p>}
          </div>

          <div>
            <Button type="submit" disabled={isUploading}>
              {isUploading ? 'Uploading...' : 'Upload Article'}
            </Button>
          </div>
        </form>
      </CardContent>
    </Card>
  )
}
// components/AdminDashboard.tsx

'use client'

import { useState } from 'react'
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
import { useToast } from "@/components/ui/use-toast"
import { ToastAction } from "@/components/ui/toast"

export default function AdminDashboard() {
  const [activeTab, setActiveTab] = useState('articles')
  const { toast } = useToast()

  const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault()
    const form = event.currentTarget as HTMLFormElement
    const formData = new FormData(form)
    
    let endpoint = ''
    switch (activeTab) {
      case 'articles':
        endpoint = 'articles'
        break
      case 'videos':
        endpoint = 'videos'
        break
      case 'livescores':
        endpoint = 'livescores'
        break
      default:
        endpoint = ''
        break
    }

    if (!endpoint) {
      toast({
        variant: "destructive",
        title: "Invalid Tab",
        description: "Please select a valid tab.",
        action: <ToastAction altText="Okay">Okay</ToastAction>,
      })
      return
    }

    try {
      const token = localStorage.getItem('adminToken')
      if (!token) throw new Error('Unauthorized')

      const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/admin/${endpoint}`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${token}`,
        },
        body: formData,
      })

      if (response.ok) {
        toast({
          title: "Success",
          description: `${endpoint.slice(0, -1)} created successfully`,
          action: <ToastAction altText="Okay">Okay</ToastAction>,
        })
        form.reset()
      } else {
        const errorData = await response.json()
        throw new Error(errorData.error || `Failed to create ${endpoint.slice(0, -1)}`)
      }
    } catch (error: any) {
      console.error(`Error creating ${activeTab.slice(0, -1)}:`, error)
      toast({
        variant: "destructive",
        title: "Error",
        description: error.message || `Failed to create ${activeTab.slice(0, -1)}`,
        action: <ToastAction altText="Try Again">Try Again</ToastAction>,
      })
    }
  }

  return (
    <Card className="w-full max-w-4xl mx-auto">
      <CardHeader>
        <CardTitle className="text-2xl font-bold">Admin Dashboard</CardTitle>
      </CardHeader>
      <CardContent>
        <Tabs value={activeTab} onValueChange={setActiveTab}>
          <TabsList className="grid w-full grid-cols-3">
            <TabsTrigger value="articles">Articles</TabsTrigger>
            <TabsTrigger value="videos">Videos</TabsTrigger>
            <TabsTrigger value="livescores">Live Scores</TabsTrigger>
          </TabsList>
          <TabsContent value="articles">
            <form onSubmit={handleSubmit} className="space-y-4 mt-4">
              <Input name="title" placeholder="Article Title" required />
              <Textarea name="content" placeholder="Article Content" required />
              <Input name="author" placeholder="Author Name" required />
              <Input name="headingImage" type="file" accept="image/*" required />
              <Button type="submit">Create Article</Button>
            </form>
          </TabsContent>
          <TabsContent value="videos">
            <form onSubmit={handleSubmit} className="space-y-4 mt-4">
              <Input name="title" placeholder="Video Title" required />
              <Input name="url" type="url" placeholder="Video URL" required />
              <Input name="thumbnail" type="file" accept="image/*" required />
              <Button type="submit">Add Video</Button>
            </form>
          </TabsContent>
          <TabsContent value="livescores">
            <form onSubmit={handleSubmit} className="space-y-4 mt-4">
              <Input name="homeTeam" placeholder="Home Team" required />
              <Input name="awayTeam" placeholder="Away Team" required />
              <Input name="date" type="datetime-local" required />
              <Button type="submit">Add Live Score</Button>
            </form>
          </TabsContent>
        </Tabs>
      </CardContent>
    </Card>
  )
}

// components/AdminLogin.tsx

'use client'

import { useState } from 'react'
import { useRouter } from 'next/navigation'
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"
import { useToast } from "@/components/ui/use-toast"
import { ToastAction } from "@/components/ui/toast"
import { FaGoogle, FaFacebook, FaTwitter } from 'react-icons/fa'
import Link from 'next/link'

export default function AdminLogin() {
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')
  const router = useRouter()
  const { toast } = useToast()

  const handleLogin = async (e: React.FormEvent) => {
    e.preventDefault()
    try {
      const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/auth/login`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email, password }),
      })
      const data = await response.json()
      if (response.ok) {
        localStorage.setItem('adminToken', data.token)
        router.push('/admin/dashboard')
        toast({
          title: "Login Successful",
          description: "You have been successfully logged in.",
        })
      } else {
        throw new Error(data.error || 'Login failed')
      }
    } catch (error) {
      toast({
        variant: "destructive",
        title: "Login Failed",
        description: error instanceof Error ? error.message : "An error occurred",
        action: <ToastAction altText="Try Again">Try Again</ToastAction>,
      })
    }
  }

  // Social Login URLs
  const socialLogins = [
    {
      name: 'Google',
      icon: <FaGoogle />,
      url: `${process.env.NEXT_PUBLIC_API_BASE_URL}/auth/google`,
      color: 'bg-red-500 hover:bg-red-600',
    },
    {
      name: 'Facebook',
      icon: <FaFacebook />,
      url: `${process.env.NEXT_PUBLIC_API_BASE_URL}/auth/facebook`,
      color: 'bg-blue-600 hover:bg-blue-700',
    },
    {
      name: 'Twitter',
      icon: <FaTwitter />,
      url: `${process.env.NEXT_PUBLIC_API_BASE_URL}/auth/twitter`,
      color: 'bg-blue-400 hover:bg-blue-500',
    },
  ]

  return (
    <div className="flex justify-center items-center min-h-screen bg-gray-100">
      <Card className="w-full max-w-md">
        <CardHeader>
          <CardTitle className="text-2xl font-bold text-center">Admin Login</CardTitle>
        </CardHeader>
        <CardContent>
          <form onSubmit={handleLogin} className="space-y-4">
            <Input
              type="email"
              placeholder="Email"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              required
            />
            <Input
              type="password"
              placeholder="Password"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              required
            />
            <Button type="submit" className="w-full">Login</Button>
          </form>

          <div className="my-4 flex items-center">
            <hr className="flex-grow border-gray-300" />
            <span className="mx-2 text-gray-500">OR</span>
            <hr className="flex-grow border-gray-300" />
          </div>

          <div className="space-y-2">
            {socialLogins.map((provider) => (
              <Button
                key={provider.name}
                variant="outline"
                className={`w-full justify-center ${provider.color}`}
                onClick={() => window.location.href = provider.url}
              >
                {provider.icon}
                <span className="ml-2">Continue with {provider.name}</span>
              </Button>
            ))}
          </div>

          <p className="mt-4 text-center text-sm text-gray-600">
            Don't have an account?{' '}
            <Link href="/admin/register" className="text-blue-500 hover:underline">
              Register
            </Link>
          </p>
        </CardContent>
      </Card>
    </div>
  )
}

// routes/admin.js
const express = require("express");
const router = express.Router();
const adminController = require("../controllers/adminController");
const { verifyToken } = require("../middlewares/auth");
const authorizeRoles = require("../middlewares/authorizeRoles");
const upload = require("../middlewares/upload");

// Protect all admin routes
router.use(verifyToken);
router.use(authorizeRoles("admin", "superuser"));

// --- Article Routes ---

// Publishers can create and update articles
router.post(
  "/articles",
  authorizeRoles("publisher", "admin", "superuser"),
  upload.single("headingImage"),
  adminController.addArticle
);

// Publishers and Admins can update articles
router.put(
  "/articles/:id",
  authorizeRoles("publisher", "admin", "superuser"),
  upload.single("headingImage"),
  adminController.updateArticle
);

// SuperUsers and Admins can delete any article
router.delete(
  "/articles/:id",
  authorizeRoles("admin", "superuser"),
  adminController.deleteArticle
);

// Reviewers can review articles
router.post(
  "/articles/:id/review",
  authorizeRoles("reviewer", "admin", "superuser"),
  adminController.reviewArticle
);

// Users can read articles
router.get(
  "/articles",
  authorizeRoles("user", "reviewer", "publisher", "admin", "superuser"),
  adminController.getAllArticles
);
router.get(
  "/articles/:id",
  authorizeRoles("user", "reviewer", "publisher", "admin", "superuser"),
  adminController.getArticleById
);


// --- News Routes ---

// Similar role-based access can be applied to news routes

module.exports = router;

// routes/articleRoutes.js

const express = require("express");
const {
  getAllArticles, // Corrected function name
  addArticle,
  getArticleById,
} = require("../controllers/adminController"); // Corrected path if using adminController.js

const router = express.Router();
const fs = require("fs");
const authenticateToken = require("../middlewares/authMiddleware");
const multer = require("multer");
const path = require("path");

// Configure Multer for file uploads
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, "uploads/"); // Temporary upload directory
  },
  filename: (req, file, cb) => {
    const uniqueSuffix = `${Date.now()}-${Math.round(Math.random() * 1e9)}`;
    cb(null, `${uniqueSuffix}-${file.originalname}`);
  },
});

const upload = multer({
  storage,
  limits: { fileSize: 5 * 1024 * 1024 }, // Limit file size to 5MB
  fileFilter: (req, file, cb) => {
    const filetypes = /jpeg|jpg|png|gif/;
    const mimetype = filetypes.test(file.mimetype);
    const extname = filetypes.test(
      path.extname(file.originalname).toLowerCase()
    );

    if (mimetype && extname) {
      return cb(null, true);
    }
    cb(new Error("Only image files are allowed!"));
  },
});

// Routes for user articles
router.get("/", getAllArticles); // Updated to match the controller function name
router.post(
  "/add",
  authenticateToken,
  upload.single("headingImage"),
  addArticle
); // POST /api/articles/add
router.get("/:id", getArticleById); // GET /api/articles/:id

module.exports = router;

// routes/auth.js

const express = require("express");
const router = express.Router();
const passport = require("passport");
const authController = require("../controllers/authController");

// Local Registration
router.post("/register", authController.register);

// Local Login
router.post("/login", authController.login);

// Logout
router.post("/logout", authController.logout);

// Verify Token
router.post("/verify-token", authController.verifyToken);

// Google OAuth Routes
router.get(
  "/google",
  passport.authenticate("google", { scope: ["profile", "email"] })
);

router.get(
  "/google/callback",
  passport.authenticate("google", {
    session: false,
    failureRedirect: "/login",
  }),
  authController.socialLoginCallback
);

// Facebook OAuth Routes
router.get(
  "/facebook",
  passport.authenticate("facebook", { scope: ["email"] })
);

router.get(
  "/facebook/callback",
  passport.authenticate("facebook", {
    session: false,
    failureRedirect: "/login",
  }),
  authController.socialLoginCallback
);

// Twitter OAuth Routes
router.get("/twitter", passport.authenticate("twitter"));

router.get(
  "/twitter/callback",
  passport.authenticate("twitter", {
    session: false,
    failureRedirect: "/login",
  }),
  authController.socialLoginCallback
);

module.exports = router;


// controllers/adminController.js
const Article = require("../models/Article");
const News = require("../models/News");
const { handleControllerError } = require("../utils/errorHandler");
const fs = require("fs");
const path = require("path");

// Helper function to delete files
const deleteFile = (filePath) => {
  fs.unlink(path.join(__dirname, "..", filePath), (err) => {
    if (err) console.error(`Failed to delete file ${filePath}:`, err);
  });
};

// --- Articles CRUD Operations ---

// Create a new article
const addArticle = async (req, res) => {
  try {
    const { title, content, author } = req.body;
    const headingImage = req.file ? `/uploads/${req.file.filename}` : null;

    if (!title || !content || !author) {
      return res.status(400).json({ message: "All fields are required." });
    }

    const newArticle = new Article({
      title,
      content,
      author,
      headingImage,
      createdBy: req.admin._id,
    });

    await newArticle.save();

    res.status(201).json({
      message: "Article created successfully.",
      article: newArticle,
    });
  } catch (error) {
    handleControllerError(error, res, "addArticle");
  }
};

// Get all articles
const getAllArticles = async (req, res) => {
  try {
    const articles = await Article.find()
      .populate("createdBy", "username")
      .sort({ createdAt: -1 });
    res.json(articles);
  } catch (error) {
    handleControllerError(error, res, "getAllArticles");
  }
};

// Get a single article by ID
const getArticleById = async (req, res) => {
  try {
    const { id } = req.params;
    const article = await Article.findById(id).populate(
      "createdBy",
      "username"
    );

    if (!article) {
      return res.status(404).json({ message: "Article not found." });
    }

    res.json(article);
  } catch (error) {
    handleControllerError(error, res, "getArticleById");
  }
};

// Update an existing article
const updateArticle = async (req, res) => {
  try {
    const { id } = req.params;
    const { title, content, author } = req.body;
    let headingImage;

    const article = await Article.findById(id);
    if (!article) {
      return res.status(404).json({ message: "Article not found." });
    }

    if (req.file) {
      // Delete the old image if it exists
      if (article.headingImage) {
        deleteFile(article.headingImage);
      }
      headingImage = `/uploads/${req.file.filename}`;
      article.headingImage = headingImage;
    }

    // Update fields if provided
    if (title) article.title = title;
    if (content) article.content = content;
    if (author) article.author = author;

    await article.save();

    res.json({ message: "Article updated successfully.", article });
  } catch (error) {
    handleControllerError(error, res, "updateArticle");
  }
};

// Delete an article
const deleteArticle = async (req, res) => {
  try {
    const { id } = req.params;

    const article = await Article.findByIdAndDelete(id);
    if (!article) {
      return res.status(404).json({ message: "Article not found." });
    }

    // Delete the heading image if it exists
    if (article.headingImage) {
      deleteFile(article.headingImage);
    }

    res.json({ message: "Article deleted successfully." });
  } catch (error) {
    handleControllerError(error, res, "deleteArticle");
  }
};
const reviewArticle = async (req, res) => {
  try {
    const { id } = req.params;
    const { review } = req.body;

    const article = await Article.findById(id);
    if (!article) {
      return res.status(404).json({ message: "Article not found." });
    }

    // Assuming you have a reviews array in your Article model
    article.reviews.push({
      reviewer: req.admin._id,
      review,
      reviewedAt: new Date(),
    });

    await article.save();

    res
      .status(200)
      .json({ message: "Article reviewed successfully.", article });
  } catch (error) {
    handleControllerError(error, res, "reviewArticle");
  }
};


// --- News CRUD Operations ---

// Create a new news item
const addNews = async (req, res) => {
  try {
    const { title, content } = req.body;
    const headingImage = req.files["headingImage"]
      ? `/uploads/${req.files["headingImage"][0].filename}`
      : null;
    const images = req.files["images"]
      ? req.files["images"].map((file) => `/uploads/${file.filename}`)
      : [];

    if (!title || !content) {
      return res
        .status(400)
        .json({ message: "Title and content are required." });
    }

    const newNews = new News({
      title,
      content,
      headingImage,
      images,
      createdBy: req.admin._id,
    });

    await newNews.save();

    res.status(201).json({
      message: "News created successfully.",
      news: newNews,
    });
  } catch (error) {
    handleControllerError(error, res, "addNews");
  }
};

// Get all news
const getAllNews = async (req, res) => {
  try {
    const newsList = await News.find()
      .populate("createdBy", "username")
      .sort({ createdAt: -1 });
    res.json(newsList);
  } catch (error) {
    handleControllerError(error, res, "getAllNews");
  }
};

// Get a single news item by ID
const getNewsById = async (req, res) => {
  try {
    const { id } = req.params;
    const news = await News.findById(id).populate("createdBy", "username");

    if (!news) {
      return res.status(404).json({ message: "News not found." });
    }

    res.json(news);
  } catch (error) {
    handleControllerError(error, res, "getNewsById");
  }
};

// Update an existing news item
const updateNews = async (req, res) => {
  try {
    const { id } = req.params;
    const { title, content } = req.body;
    let headingImage;
    let images;

    const news = await News.findById(id);
    if (!news) {
      return res.status(404).json({ message: "News not found." });
    }

    if (req.files["headingImage"]) {
      // Delete the old heading image if it exists
      if (news.headingImage) {
        deleteFile(news.headingImage);
      }
      headingImage = `/uploads/${req.files["headingImage"][0].filename}`;
      news.headingImage = headingImage;
    }

    if (req.files["images"] && req.files["images"].length > 0) {
      // Optionally delete old carousel images
      news.images.forEach((img) => deleteFile(img));
      images = req.files["images"].map((file) => `/uploads/${file.filename}`);
      news.images = images;
    }

    // Update fields if provided
    if (title) news.title = title;
    if (content) news.content = content;

    await news.save();

    res.json({ message: "News updated successfully.", news });
  } catch (error) {
    handleControllerError(error, res, "updateNews");
  }
};

// Delete a news item
const deleteNews = async (req, res) => {
  try {
    const { id } = req.params;

    const news = await News.findByIdAndDelete(id);
    if (!news) {
      return res.status(404).json({ message: "News not found." });
    }

    // Delete heading and carousel images if they exist
    if (news.headingImage) {
      deleteFile(news.headingImage);
    }
    news.images.forEach((img) => deleteFile(img));

    res.json({ message: "News deleted successfully." });
  } catch (error) {
    handleControllerError(error, res, "deleteNews");
  }
};

module.exports = {
  // Articles
  addArticle,
  getAllArticles,
  getArticleById,
  updateArticle,
  deleteArticle,

  // News
  addNews,
  getAllNews,
  getNewsById,
  updateNews,
  deleteNews,
  reviewArticle,
};

const Article = require("../models/Article");
const { handleControllerError } = require("../utils/errorHandler");

// Function to handle uploading a new article
const addArticle = async (req, res) => {
  try {
    const { title, content, author } = req.body;
    const headingImage = req.file ? `/uploads/${req.file.filename}` : null;

    if (!title || !content || !author) {
      return res.status(400).json({ message: "All fields are required." });
    }

    const newArticle = new Article({
      title,
      content,
      author,
      headingImage,
    });

    await newArticle.save();

    res
      .status(201)
      .json({
        message: "Article uploaded successfully.",
        articleId: newArticle._id,
      });
  } catch (error) {
    handleControllerError(error, res, "addArticle");
  }
};

// Function to fetch all articles
const getArticles = async (req, res) => {
  try {
    const articles = await Article.find().sort({ createdAt: -1 });
    res.json(articles);
  } catch (error) {
    handleControllerError(error, res, "getArticles");
  }
};

// Function to fetch a single article by ID
const getArticleById = async (req, res) => {
  try {
    const { id } = req.params;
    const article = await Article.findById(id);

    if (!article) {
      return res.status(404).json({ message: "Article not found." });
    }

    res.json(article);
  } catch (error) {
    handleControllerError(error, res, "getArticleById");
  }
};

module.exports = {
  getArticles,
  addArticle,
  getArticleById,
};

// controllers/authController.js

const Admin = require("../models/Admin");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");

// Helper function to generate JWT
const generateToken = (admin) => {
  return jwt.sign(
    { _id: admin._id, role: admin.role },
    process.env.JWT_SECRET,
    { expiresIn: "7d" }
  );
};

// Register Controller
exports.register = async (req, res) => {
  try {
    const { username, email, password } = req.body;

    // Validate input
    if (!username || !email || !password) {
      return res.status(400).json({ error: "All fields are required." });
    }

    // Check if email or username already exists
    const existingAdmin = await Admin.findOne({
      $or: [{ email }, { username }],
    });

    if (existingAdmin) {
      return res.status(400).json({ error: "Admin already exists." });
    }

    // Hash password
    const hashedPassword = await bcrypt.hash(password, 10);

    // Create new admin
    const newAdmin = new Admin({
      username,
      email,
      password: hashedPassword,
    });

    await newAdmin.save();

    res.status(201).json({ message: "Admin registered successfully." });
  } catch (error) {
    console.error("Registration Error:", error);
    res.status(500).json({ error: "Server error during registration." });
  }
};

// Login Controller
exports.login = async (req, res) => {
  try {
    const { email, password } = req.body;

    // Validate input
    if (!email || !password) {
      return res.status(400).json({ error: "All fields are required." });
    }

    // Find admin by email
    const admin = await Admin.findOne({ email });

    if (!admin) {
      return res.status(400).json({ error: "Invalid credentials." });
    }

    // Compare passwords
    if (!admin.password) {
      // Handle users without passwords (e.g., social logins)
      return res
        .status(400)
        .json({ error: "Please log in using a social account." });
    }

    const isMatch = await bcrypt.compare(password, admin.password);

    if (!isMatch) {
      return res.status(400).json({ error: "Invalid credentials." });
    }

    // Generate JWT
    const token = generateToken(admin);

    // Determine if the user is a superuser
    if (admin.role === "superuser") {
      res.json({ token, role: "superuser" });
    } else {
      res.json({ token, role: admin.role });
    }
  } catch (error) {
    console.error("Login Error:", error);
    res.status(500).json({ error: "Server error during login." });
  }
};

// Logout Controller
exports.logout = (req, res) => {
  // Since JWT is stateless, logout can be handled on the client by deleting the token.
  // To implement server-side logout (like token blacklisting), additional setup is required.
  res.json({
    message: "Logout successful. Please delete the token on client side.",
  });
};

// Verify Token Controller
exports.verifyToken = async (req, res) => {
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith("Bearer ")) {
    return res
      .status(401)
      .json({ message: "Authorization header missing or malformed." });
  }
  const token = authHeader.split(" ")[1];

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    const admin = await Admin.findById(decoded._id);
    if (!admin) {
      return res.status(401).json({ message: "Invalid token." });
    }
    res.json({ _id: admin._id, role: admin.role });
  } catch (err) {
    return res.status(401).json({ message: "Invalid token." });
  }
};

// Social Login Callback Controller
exports.socialLoginCallback = async (req, res) => {
  try {
    const admin = req.user;

    // Generate JWT
    const token = generateToken(admin);

    // Redirect or respond with token
    // For APIs, it's common to send the token in the response or set it as a query parameter
    // For simplicity, we'll redirect to a front-end route with the token as a query param
    res.redirect(
      `${process.env.FRONTEND_URL}/social-login-success?token=${token}`
    );
  } catch (error) {
    console.error("Social Login Callback Error:", error);
    res.status(500).json({ error: "Server error during social login." });
  }
};
// config/passport.js
const passport = require("passport");
const JwtStrategy = require("passport-jwt").Strategy;
const ExtractJwt = require("passport-jwt").ExtractJwt;
const GoogleStrategy = require("passport-google-oauth20").Strategy;
const FacebookStrategy = require("passport-facebook").Strategy;
const TwitterStrategy = require("passport-twitter").Strategy;
const Admin = require("../models/Admin");
const dotenv = require("dotenv");

dotenv.config();

// JWT Options
const opts = {
  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
  secretOrKey: process.env.JWT_SECRET,
};

// JWT Strategy
passport.use(
  new JwtStrategy(opts, async (jwt_payload, done) => {
    try {
      const admin = await Admin.findById(jwt_payload._id);
      if (admin) {
        return done(null, admin);
      }
      return done(null, false);
    } catch (err) {
      return done(err, false);
    }
  })
);

// Google Strategy
passport.use(
  new GoogleStrategy(
    {
      clientID: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
      callbackURL: "/auth/google/callback",
    },
    async (accessToken, refreshToken, profile, done) => {
      try {
        // Check if admin with this Google ID exists
        let admin = await Admin.findOne({ googleId: profile.id });

        if (admin) {
          return done(null, admin);
        }

        // If not, check if an admin with the same email exists
        admin = await Admin.findOne({ email: profile.emails[0].value });

        if (admin) {
          // Link Google account
          admin.googleId = profile.id;
          admin.profilePicture = profile.photos[0].value;
          await admin.save();
          return done(null, admin);
        }

        // If no admin exists, create a new one
        const newAdmin = new Admin({
          username: profile.displayName,
          email: profile.emails[0].value,
          googleId: profile.id,
          profilePicture: profile.photos[0].value,
        });

        await newAdmin.save();
        return done(null, newAdmin);
      } catch (error) {
        return done(error, false);
      }
    }
  )
);

// Facebook Strategy
passport.use(
  new FacebookStrategy(
    {
      clientID: process.env.FACEBOOK_APP_ID,
      clientSecret: process.env.FACEBOOK_APP_SECRET,
      callbackURL: "/auth/facebook/callback",
      profileFields: ["id", "displayName", "emails", "photos"],
    },
    async (accessToken, refreshToken, profile, done) => {
      try {
        let admin = await Admin.findOne({ facebookId: profile.id });

        if (admin) {
          return done(null, admin);
        }

        // Check if admin with the same email exists
        const email = profile.emails ? profile.emails[0].value : null;
        if (email) {
          admin = await Admin.findOne({ email });

          if (admin) {
            // Link Facebook account
            admin.facebookId = profile.id;
            admin.profilePicture = profile.photos[0].value;
            await admin.save();
            return done(null, admin);
          }
        }

        // Create a new admin
        const newAdmin = new Admin({
          username: profile.displayName,
          email: email,
          facebookId: profile.id,
          profilePicture: profile.photos[0].value,
        });

        await newAdmin.save();
        return done(null, newAdmin);
      } catch (error) {
        return done(error, false);
      }
    }
  )
);

// Twitter Strategy
passport.use(
  new TwitterStrategy(
    {
      consumerKey: process.env.TWITTER_CONSUMER_KEY,
      consumerSecret: process.env.TWITTER_CONSUMER_SECRET,
      callbackURL: "/auth/twitter/callback",
      includeEmail: true,
    },
    async (token, tokenSecret, profile, done) => {
      try {
        let admin = await Admin.findOne({ twitterId: profile.id });

        if (admin) {
          return done(null, admin);
        }

        // Note: Twitter may not always provide email
        const email = profile.emails ? profile.emails[0].value : null;
        if (email) {
          admin = await Admin.findOne({ email });

          if (admin) {
            // Link Twitter account
            admin.twitterId = profile.id;
            admin.profilePicture = profile.photos[0].value;
            await admin.save();
            return done(null, admin);
          }
        }

        // Create a new admin
        const newAdmin = new Admin({
          username: profile.displayName,
          email: email, // May be undefined
          twitterId: profile.id,
          profilePicture: profile.photos[0].value,
        });

        await newAdmin.save();
        return done(null, newAdmin);
      } catch (error) {
        return done(error, false);
      }
    }
  )
);

Can you setup front end according to backend and also there's So that I can upload article review article like creating an improvement and also   what are things coming from backend sets up in frontend 
To utilize it fully in files I have provided only necessary changes are gonna reflect
localhost:5000/api is backend url