import React, {
  createContext,
  useContext,
  useState,
  useEffect,
  useRef,
} from "react";
import cruiseImg from "./images/cruise.jpg";
import discGolfImg from "./images/disc_golf_ace.jpg";
import odinImg from "./images/odin.jpg";
import {
  BrowserRouter as Router,
  Routes,
  Route,
  Link,
  useNavigate,
} from "react-router-dom";
import { useForm } from "react-hook-form";
import { BlogViewer } from "./utils/BlogViewer";
import { RequireAdmin } from "./utils/RouteGuard";
import { AdminPage } from "./utils/AdminPage";
import { EditBlog } from "./utils/EditBlog";
import Unauthorized from "./utils/UnauthorizedPage";
import {
  FaGithub,
  FaGitAlt,
  FaLinkedin,
  FaTwitter,
  FaSun,
  FaMoon,
} from "react-icons/fa";
import type { Blog } from "./utils/types";
import { countWords } from "./utils/countWords";
import { API_URL } from "./utils/constants";

// Auth Context
interface AuthContextProps {
  isAuthenticated: boolean;
  login: (token: string, user_id: number) => void;
  logout: () => void;
}
const AuthContext = createContext<AuthContextProps>({
  isAuthenticated: false,
  login: () => {},
  logout: () => {},
});
export const useAuth = () => useContext(AuthContext);

const AuthProvider: React.FC<{ children: React.ReactNode }> = ({
  children,
}) => {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const navigate = useNavigate();

  useEffect(() => {
    const token = localStorage.getItem("token");
    setIsAuthenticated(!!token);
  }, []);

  const login = (token: string, user_id: number) => {
    localStorage.setItem("token", token);
    localStorage.setItem("user_id", user_id.toString());
    setIsAuthenticated(true);
  };

  const logout = () => {
    localStorage.removeItem("token");
    localStorage.removeItem("user_id");
    setIsAuthenticated(false);
    navigate("/signin");
  };

  return (
    <AuthContext.Provider value={{ isAuthenticated, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
};

function BlogPage() {
  const { isAuthenticated } = useAuth();
  const navigate = useNavigate();
  const [blogs, setBlogs] = useState<Blog[]>([]);

  useEffect(() => {
    fetch(`${API_URL}/blogs`, {
      method: "GET",
      headers: {
        "Content-Type": "application/json",
      },
    })
      .then((res) => res.json())
      .then((data: Blog[]) => setBlogs(data))
      .catch((err) => console.error(err));
  }, []);

  return (
    <div>
      <div className="flex justify-end mb-4">
        <button
          onClick={() =>
            isAuthenticated ? navigate("/create") : navigate("/signin")
          }
          className="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700"
        >
          Create
        </button>
      </div>
      <div className="space-y-4">
        {blogs.map((blog) => (
          <Link
            key={blog.id}
            to={`/blog/${blog.id}`}
            className="block p-4 border rounded hover:bg-gray-100 dark:hover:bg-gray-800"
          >
            <h3 className="text-xl font-semibold">{blog.title}</h3>
            <p className="italic text-gray-600 dark:text-gray-400">
              {blog.description}
            </p>
            <p className="text-sm text-gray-500">By {blog.author_name}</p>
          </Link>
        ))}
      </div>
    </div>
  );
}

// Page for creating a blog post
function CreateBlog() {
  const [fileName, setFileName] = useState<string>("");
  const [title, setTitle] = useState("");
  const [description, setDescription] = useState("");
  const [authorName, setAuthorName] = useState("");
  const [content, setContent] = useState<string>("");
  const navigate = useNavigate();

  const handleFile = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = () => {
      const text = reader.result as string;
      setContent(text);
      setFileName(file.name);
      const baseName = file.name.replace(/\.[^.]+$/, "");
      setTitle(baseName);
      setAuthorName(authorName);
    };
    reader.readAsText(file);
  };

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    const userId = Number(localStorage.getItem("user_id"));
    try {
      const body = {
        title,
        author_id: userId, // still from localStorage
        author_name: authorName, // from the form field
        description: description,
        body: content,
        created_at: new Date().toISOString(),
        updated_at: new Date().toISOString(),
        published_at: new Date().toISOString(),
        word_count: countWords(content),
      };
      await fetch(`${API_URL}/blogs`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(body),
      });
      navigate("/blog");
    } catch (err: any) {
      alert(err.message);
    }
  };

  return (
    <div className="max-w-xl mx-auto py-10 space-y-6">
      <h2 className="text-2xl font-bold">Create Post</h2>
      <div className="flex space-x-4">
        <label className="px-4 py-2 bg-gray-200 dark:bg-gray-700 rounded cursor-pointer hover:bg-gray-300 dark:hover:bg-gray-600">
          Upload File
          <input
            type="file"
            accept=".txt,.md"
            onChange={handleFile}
            className="hidden"
          />
        </label>
      </div>
      {fileName && (
        <form onSubmit={handleSubmit} className="space-y-4">
          <div>
            <label htmlFor="title" className="block text-sm font-medium mb-1">
              Title
            </label>
            <input
              id="title"
              type="text"
              value={title}
              onChange={(e) => setTitle(e.target.value)}
              className="w-full border border-gray-300 dark:border-gray-600 rounded px-3 py-2"
            />
          </div>
          <div>
            <label htmlFor="author" className="block text-sm font-medium mb-1">
              Author
            </label>
            <input
              id="author"
              type="text"
              value={authorName}
              onChange={(e) => setAuthorName(e.target.value)}
              className="w-full border border-gray-300 dark:border-gray-600 rounded px-3 py-2"
            />
          </div>
          <div>
            <label
              htmlFor="description"
              className="block text-sm font-medium mb-1"
            >
              Description
            </label>
            <input
              id="description"
              type="text"
              value={description}
              onChange={(e) => setDescription(e.target.value)}
              className="w-full border border-gray-300 dark:border-gray-600 rounded px-3 py-2"
            />
          </div>
          <div>
            <label htmlFor="content" className="block text-sm font-medium mb-1">
              Content
            </label>
            <textarea
              id="content"
              rows={10}
              value={content}
              onChange={(e) => setContent(e.target.value)}
              className="w-full border border-gray-300 dark:border-gray-600 rounded px-3 py-2 max-h-96 overflow-y-auto resize-none"
            />
          </div>
          <button
            type="submit"
            className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
          >
            Submit
          </button>
        </form>
      )}
    </div>
  );
}

function App() {
  // Initialize theme from localStorage or default to light
  const [darkMode, setDarkMode] = useState<boolean>(() => {
    return localStorage.getItem("theme") === "dark";
  });

  // Sync dark mode state with <html> class and localStorage
  useEffect(() => {
    if (darkMode) {
      document.documentElement.classList.add("dark");
      localStorage.setItem("theme", "dark");
    } else {
      document.documentElement.classList.remove("dark");
      localStorage.setItem("theme", "light");
    }
  }, [darkMode]);

  return (
    <Router>
      <AuthProvider>
        <div className="min-h-screen bg-gray-100 dark:bg-gray-900 text-gray-900 dark:text-gray-100 transition-colors duration-300">
          <AppBar
            darkMode={darkMode}
            toggleDarkMode={() => setDarkMode((prev) => !prev)}
          />
          <div className="p-4">
            <Routes>
              <Route path="/" element={<LandingPage />} />
              <Route path="/blog" element={<BlogPage />} />
              <Route path="/blog/:slug" element={<BlogViewer />} />
              <Route path="/blog/:slug/edit" element={<EditBlog />} />
              <Route path="/about" element={<About />} />
              <Route path="/contact" element={<Contact />} />
              <Route
                path="/admin"
                element={
                  <RequireAdmin>
                    <AdminPage />
                  </RequireAdmin>
                }
              />
              <Route path="/unauthorized" element={<Unauthorized />} />
              <Route path="/register" element={<Register />} />
              <Route path="/signin" element={<SignIn />} />
              <Route path="/profile" element={<Profile />} />
              <Route path="/create" element={<CreateBlog />} />
            </Routes>
          </div>
        </div>
      </AuthProvider>
    </Router>
  );
}

function AppBar({
  darkMode,
  toggleDarkMode,
}: {
  darkMode: boolean;
  toggleDarkMode: () => void;
}) {
  const { isAuthenticated, logout } = useAuth();
  const [menuOpen, setMenuOpen] = useState(false);
  const menuRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (
        menuOpen &&
        menuRef.current &&
        !menuRef.current.contains(event.target as Node)
      ) {
        setMenuOpen(false);
      }
    };
    document.addEventListener("mousedown", handleClickOutside);
    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, [menuOpen]);

  return (
    <nav className="bg-white dark:bg-gray-800 shadow p-4 flex items-center relative">
      <Link to="/" className="font-bold text-blue-600 dark:text-blue-400">
        Home
      </Link>
      <Link
        to="/blog"
        className="ml-4 text-gray-800 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400"
      >
        Blog
      </Link>
      <Link
        to="/about"
        className="ml-4 text-gray-800 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400"
      >
        About Me
      </Link>
      <Link
        to="/contact"
        className="ml-4 text-gray-800 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400"
      >
        Contact
      </Link>
      <div className="ml-auto flex items-center space-x-4">
        {!isAuthenticated ? (
          <>
            <Link
              to="/register"
              className="px-3 py-1 bg-blue-600 text-white rounded hover:bg-blue-700"
            >
              Register
            </Link>
            <Link
              to="/signin"
              className="px-3 py-1 bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-gray-200 rounded hover:bg-gray-300 dark:hover:bg-gray-600"
            >
              Sign In
            </Link>
          </>
        ) : (
          <div className="relative" ref={menuRef}>
            <button
              onClick={() => setMenuOpen(!menuOpen)}
              className="w-8 h-8 rounded-full bg-gray-200 dark:bg-gray-700 flex items-center justify-center"
            >
              <span className="text-gray-700 dark:text-gray-200">U</span>
            </button>
            {menuOpen && (
              <div className="absolute right-0 mt-2 w-32 bg-white dark:bg-gray-700 shadow rounded">
                <Link
                  to="/profile"
                  className="block px-4 py-2 text-gray-800 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600"
                >
                  Profile
                </Link>
                <button
                  onClick={logout}
                  className="w-full text-left block px-4 py-2 text-gray-800 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600"
                >
                  Sign Out
                </button>
              </div>
            )}
          </div>
        )}
        <button
          onClick={toggleDarkMode}
          className="text-xl p-1 bg-gray-200 dark:bg-gray-700 rounded-full"
        >
          {darkMode ? <FaMoon /> : <FaSun />}
        </button>
      </div>
    </nav>
  );
}

// Pages and forms
function LandingPage() {
  return (
    <div className="text-center py-10">
      <h1 className="text-4xl font-bold mb-4">Welcome to My Site</h1>
      <p className="text-lg text-gray-700 dark:text-gray-300">
        Explore my blog, learn about me, or get in touch.
      </p>
    </div>
  );
}

function About() {
  return (
    <div className="py-10">
      <div className="flex justify-center items-end space-x-4 flex-wrap">
        {[cruiseImg, discGolfImg, odinImg].map((src, i) => (
          <img
            key={i}
            src={src}
            alt={["Cruise", "Disc golf ace", "Odin"][i]}
            className="
          rounded-full 
          aspect-square 
          object-cover
          w-1/3 max-w-[120px]     /* small screens: 33% of container, up to 120px */
          sm:w-1/4 sm:max-w-[150px] /* ≥640px: 25% up to 150px */
          md:w-1/6 md:max-w-[200px] /* ≥768px: ~16% up to 200px */
          lg:w-1/8 lg:max-w-[250px] /* ≥1024px: 12.5% up to 250px */
        "
          />
        ))}
      </div>
      <div className="text-center mt-8 px-4">
        <h2 className="text-3xl font-bold mb-4">About Me</h2>
        <p className="text-lg text-gray-700 dark:text-gray-300 max-w-2xl mx-auto">
          I’m Alex, a full-stack engineer at Whisker, working on backend one
          minute, mobile tweaks the next, and firmware the day after. Learning
          new tech is something I'm passionate about, and I’m all about
          spreading that knowledge fast. Off-duty you’ll catch me reading a
          bunch, writing (ironically, on my blog, which you are currently
          viewing), exploring the outdoors with my dogs (and my girlfriend,
          trust me she’s real!), or rolling dice as a D&amp;D sorcerer. Here
          you’ll find book thoughts, code experiments, and random shower
          thoughts. Thanks for stopping by!
        </p>
      </div>
      <div className="mt-8 flex flex-col items-center space-y-2">
        <a
          href="https://github.com/amuszyn"
          className="flex items-center space-x-2 text-blue-600 hover:underline"
        >
          <FaGithub />
          <span>github.com/amuszyn</span>
        </a>
        <a
          href="https://gitea.muszyn.dev/"
          className="flex items-center space-x-2 text-blue-600 hover:underline"
        >
          <FaGitAlt />
          <span>gitea.muszyn.dev/</span>
        </a>
        <a
          href="https://www.linkedin.com/in/almuszynski/"
          className="flex items-center space-x-2 text-blue-600 hover:underline"
        >
          <FaLinkedin />
          <span>linkedin.com/in/almuszynski</span>
        </a>
        <a
          href="https://x.com/Muszynlol"
          className="flex items-center space-x-2 text-blue-600 hover:underline"
        >
          <FaTwitter />
          <span>x.com/Muszynlol</span>
        </a>
      </div>
    </div>
  );
}

function Contact() {
  return (
    <div className="text-center py-10">
      <h2 className="text-2xl font-bold mb-4">Contact</h2>
      <p>Contact page content coming soon.</p>
    </div>
  );
}

function Profile() {
  return (
    <div className="text-center py-10">
      <h2 className="text-2xl font-bold mb-4">Profile</h2>
      <p>Profile page coming soon.</p>
    </div>
  );
}

// Registration form with API integration
interface RegisterForm {
  username: string;
  email: string;
  password: string;
  confirmPassword: string;
}

function Register() {
  const navigate = useNavigate();
  const {
    register,
    handleSubmit,
    watch,
    formState: { errors },
  } = useForm<RegisterForm>();

  const onSubmit = async (data: RegisterForm) => {
    try {
      const response = await fetch(`${API_URL}/register`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          username: data.username,
          email: data.email,
          password: data.password,
        }),
      });
      if (!response.ok) {
        const err = await response.json();
        throw new Error(err.detail || "Registration failed");
      }
      navigate("/signin");
    } catch (err: any) {
      alert(err.message);
    }
  };

  return (
    <div className="max-w-md mx-auto py-10">
      <h2 className="text-2xl font-bold mb-6 text-center">Register</h2>
      <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
        <div>
          <label htmlFor="username" className="block text-sm font-medium mb-1">
            Username
          </label>
          <input
            id="username"
            {...register("username", { required: true })}
            className="w-full border border-gray-300 dark:border-gray-600 rounded px-3 py-2"
          />
          {errors.username && (
            <span className="text-red-600 text-sm">Username is required</span>
          )}
        </div>

        <div>
          <label htmlFor="email" className="block text-sm font-medium mb-1">
            Email
          </label>
          <input
            id="email"
            type="email"
            {...register("email", {
              required: true,
              pattern: /^\S+@\S+\.\S+$/,
            })}
            className="w-full border border-gray-300 dark:border-gray-600 rounded px-3 py-2"
          />
          {errors.email && (
            <span className="text-red-600 text-sm">
              Valid email is required
            </span>
          )}
        </div>

        <div>
          <label htmlFor="password" className="block text-sm font-medium mb-1">
            Password
          </label>
          <input
            id="password"
            type="password"
            {...register("password", {
              required: true,
              pattern: /(?=.*[A-Z])(?=.*\d).+/,
            })}
            className="w-full border border-gray-300 dark:border-gray-600 rounded px-3 py-2"
          />
          {errors.password && (
            <span className="text-red-600 text-sm">
              Password must include uppercase and number
            </span>
          )}
        </div>

        <div>
          <label
            htmlFor="confirmPassword"
            className="block text-sm font-medium mb-1"
          >
            Confirm Password
          </label>
          <input
            id="confirmPassword"
            type="password"
            {...register("confirmPassword", {
              validate: (value) =>
                value === watch("password") || "Passwords do not match",
            })}
            className="w-full border border-gray-300 dark:border-gray-600 rounded px-3 py-2"
          />
          {errors.confirmPassword && (
            <span className="text-red-600 text-sm">
              {errors.confirmPassword.message}
            </span>
          )}
        </div>

        <button
          type="submit"
          className="w-full bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700"
        >
          Register
        </button>
      </form>
    </div>
  );
}

// Sign-in form with API integration
interface SignInForm {
  identifier: string;
  password: string;
}

function SignIn() {
  const navigate = useNavigate();
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<SignInForm>();
  const { login } = useAuth();

  const onSubmit = async (data: SignInForm) => {
    try {
      const body = new URLSearchParams();
      body.append("username", data.identifier);
      body.append("password", data.password);

      const response = await fetch(`${API_URL}/login`, {
        method: "POST",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        body: body.toString(),
      });

      if (!response.ok) {
        const err = await response.json();
        throw new Error(err.detail || "Login failed");
      }

      const tokenData = await response.json();
      alert(response);
      login(tokenData.access_token, tokenData.user_id);
      navigate("/");
    } catch (err: any) {
      alert(err.message);
    }
  };

  return (
    <div className="max-w-md mx-auto py-10">
      <h2 className="text-2xl font-bold mb-6 text-center">Sign In</h2>
      <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
        <div>
          <label
            htmlFor="identifier"
            className="block text-sm font-medium mb-1"
          >
            Username or Email
          </label>
          <input
            id="identifier"
            {...register("identifier", { required: true })}
            className="w-full border border-gray-300 dark:border-gray-600 rounded px-3 py-2"
          />
          {errors.identifier && (
            <span className="text-red-600 text-sm">This field is required</span>
          )}
        </div>

        <div>
          <label
            htmlFor="signinPassword"
            className="block text-sm font-medium mb-1"
          >
            Password
          </label>
          <input
            id="signinPassword"
            type="password"
            {...register("password", { required: true })}
            className="w-full border border-gray-300 dark:border-gray-600 rounded px-3 py-2"
          />
          {errors.password && (
            <span className="text-red-600 text-sm">Password is required</span>
          )}
        </div>

        <button
          type="submit"
          className="w-full bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700"
        >
          Sign In
        </button>
      </form>
    </div>
  );
}

export default App;
