import RootLayout from "~/layout/RootLayout";
import type { Route } from "../+types/root";
import { useNavigate, useParams } from "react-router";
import { useEffect, useState, type FormEventHandler } from "react";
import { API } from "~/api/api";
import Icon, { ICONS } from "~/components/Icon";
import { getTagColor } from "../utils/tags";

import type { Post } from "~/types/post";
import Modal from "~/components/Modal";
import type { Comment } from "~/types/comment";
import Loading from "~/components/Loading";
import { useAuth } from "~/context/AuthContext";
import { NotFound } from "~/components/NotFound";
import type { PaginatedResponse } from "~/types/PaginatedResponse";

type ActionButtonProps = {
  onClick?: React.MouseEventHandler<HTMLButtonElement>;
  icon: string;
  children: React.ReactNode;
  className?: string;
};

export function meta({}: Route.MetaArgs) {
  return [
    { title: "ImgBoard - Viewing Post" },
  ];
}

function formatDate(dateString: string): string {
  const date = new Date(dateString);
  return date.toLocaleDateString(undefined, {
    year: 'numeric',
    month: 'short',
    day: 'numeric',
    hour: '2-digit',
    minute: '2-digit'
  });
}

export default function Post() {
  const { id } = useParams();
  const navigate = useNavigate();

  if (!id) {
    return <NotFound/>
  }
  
  const idNum = parseInt(id, 10);
  if (isNaN(idNum)) {
    return <NotFound/>
  }

  const [post, setPost] = useState<Post|null>(null);
  const [isEditPostModalOpen, setIsEditPostModalOpen] = useState(false);

  const [paginatedComments, setPaginatedComments] = useState<PaginatedResponse<Comment> | null>(null);
  const [currentCommentPage, setCurrentCommentPage] = useState(1);
  const [commentToEdit, setCommentToEdit] = useState<Comment|null>(null);
  const [isEditCommentModalOpen, setIsEditCommentModalOpen] = useState(false);


  console.log("Post ID from params:", id);

  useEffect(() => {
    // Fetch post details using the id

    console.log(`Fetching post with id: ${id}`);

    async function fetchData() {
      const post = await API.fetchPostById(idNum);
      setPost(post);
    }
    fetchData();
  }, [id]);

  useEffect(() => {
    async function fetchComments() {
        const comments = await API.fetchCommentsByPostId(idNum, currentCommentPage);
        setPaginatedComments(comments);
    }
    fetchComments();
  }, [id, currentCommentPage]);

  const { user } = useAuth();

  if (!post) {
    return <RootLayout>
      <Loading />
    </RootLayout>;
  }


  /**
   * Button component for actions like Edit, Delete, View Raw, etc.
   */
  const ActionButton: React.FC<ActionButtonProps> = ({ onClick, icon, children, className }) => (
    <button onClick={onClick} className={`flex items-center space-x-1.5 font-semibold px-3 py-1.5 rounded-md hover:bg-opacity-80 transition-colors text-sm ${className}`}>
      <Icon path={icon} className="w-4 h-4" />
      <span>{children}</span>
    </button>
  );

  const Pagination = ({
    itemsPerPage,
    totalItems,
    paginate,
    currentPage,
  }: {
    itemsPerPage: number;
    totalItems: number;
    paginate: (pageNumber: number) => void;
    currentPage: number;
  }) => {
    const pageNumbers = [];
    for (let i = 1; i <= Math.ceil(totalItems / itemsPerPage); i++) { pageNumbers.push(i); }
    if(pageNumbers.length <= 1) return null;
    return (
      <nav className="mt-4 flex justify-center">
        <ul className="flex items-center space-x-2">
          {pageNumbers.map(number => (
            <li key={number}>
              <button onClick={() => paginate(number)} className={`px-3 py-1 rounded-md transition-colors text-sm ${ currentPage === number ? 'bg-blue-500 text-white' : 'bg-white text-gray-700 hover:bg-gray-100'}`}>
                {number}
              </button>
            </li>
          ))}
        </ul>
      </nav>
    );
  };

  const EditPostModal = () => {
    const [title, setTitle] = useState('');
    const [description, setDescription] = useState('');
    const [tags, setTags] = useState('');
    const [error, setError] = useState('');

    useEffect(() => {
      if (post) {
        setTitle(post.title);
        setDescription(post.description);
        setTags(post.tags.map(t => t.name).join(' '));
      }
    }, [post]);

    const handleSubmit: FormEventHandler = async (e) => {
      e.preventDefault();
      setError('');
      if (!user) return;
      const enteredTags = tags.split(' ').filter(t => t);

      if (title && description && tags) {
        const res = await API.updatePost(post.id, title, description, enteredTags, user);
        const data = await res.json();
        if (!res.ok) {
          setError(data.detail || "Failed to update post.");
          return;
        }
        setPost(data);
        setIsEditPostModalOpen(false);
      }
    };

    if (!post) return null;

    return (
      <Modal isOpen={isEditPostModalOpen} onClose={() => setIsEditPostModalOpen(false)}>
        <h2 className="text-2xl font-bold mb-4">Edit Post</h2>
        <form onSubmit={handleSubmit}>
          <div className="mb-4">
            <label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="edit-post-title">Title</label>
            <input id="edit-post-title" type="text" value={title} onChange={(e) => setTitle(e.target.value)} className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700"/>
          </div>
          <div className="mb-4">
            <label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="edit-post-description">Description</label>
            <textarea id="edit-post-description" rows={3} value={description} onChange={(e) => setDescription(e.target.value)} className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700"/>
          </div>
          <div className="mb-6">
            <label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="edit-post-tags">Tags</label>
            <input id="edit-post-tags" type="text" value={tags} onChange={(e) => setTags(e.target.value)} className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700"/>
          </div>
          {error && <p className="text-red-500 text-xs italic mb-4">{error}</p>}
          <div className="flex items-center justify-end">
            <button type="submit" className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">Save Changes</button>
          </div>
        </form>
      </Modal>
    );
  };

  const canManagePost = user && (user.isAdmin || user.id === post.author.userId);

  /**
   * Called when a button to edit a post is clicked.
   */
  const onOpenEditPostModal = () => {
    setIsEditPostModalOpen(true);
  }

  /**
   * Called when a button to delete a post is clicked.
   */
  const onPostDelete = async () => {
    if (!user) return;
    const res = await API.deletePost(post.id, user)
    if (!res.ok) {
      alert("Failed to delete post.");
      return;
    }
    await navigate('/')
  };


  const onAddComment = async (postId: number, commentText: string) => {
    if (!user) return;
    const res = await API.postComment(postId, commentText, user);
    if (!res.ok) {
      alert("Failed to add comment");
      return;
    }
    const newComment: Comment = await res.json();

    // Refetch comments if this is the first one.
    if (!paginatedComments || paginatedComments.totalCount === 0) {
      const comments = await API.fetchCommentsByPostId(idNum, 1);
      setPaginatedComments(comments);
      setCurrentCommentPage(1);
      return;
    }
    
    const totalPages = Math.ceil((paginatedComments.totalCount + 1) / paginatedComments.pageSize);
    if (currentCommentPage !== totalPages) {
      setCurrentCommentPage(totalPages);
    } else {
      setPaginatedComments(prev => {
        if (!prev) return null;
        // If current page is not full, just add the comment
        if (prev.items.length < prev.pageSize) {
          return {
            ...prev,
            items: [...prev.items, newComment],
            totalCount: prev.totalCount + 1
          };
        } else {
          // This case is unlikely if totalPages is calculated correctly, but as a fallback, we refetch.
          setCurrentCommentPage(totalPages);
          return prev;
        }
      });
    }
  };
  
  const handleOpenEditCommentModal = (comment: Comment) => {
    setCommentToEdit(comment);
    setIsEditCommentModalOpen(true);
  };

  const onDeleteComment = async (postId: number, commentId: number) => {
    if (!user || !paginatedComments) return;
    const res = await API.deleteComment(postId, commentId, user);
    if (!res.ok) {
      alert("Failed to delete comment.");
      return;
    }
    
    setPaginatedComments(prev => {
      if (!prev) return null;
      const newItems = prev.items.filter(c => c.id !== commentId);
      const newTotalCount = prev.totalCount - 1;

      if (newItems.length === 0 && currentCommentPage > 1) {
        setCurrentCommentPage(currentCommentPage - 1);
        return { ...prev, items: newItems, totalCount: newTotalCount };
      }
      return { ...prev, items: newItems, totalCount: newTotalCount };
    });
  };



  //const allTags = [...new Set(posts.flatMap(p => p.tags))];

  const CommentForm = () => {
    const [error, setError] = useState('');
    const [commentText, setCommentText] = useState('');
    const handleSubmit: FormEventHandler = async (e) => {
      setError('');
      e.preventDefault();
      if (!commentText.trim()) return;
      if (!user) return;
      await onAddComment(post.id, commentText);
      setCommentText('');
    };
    return (
      <form onSubmit={handleSubmit} className="mt-6">
        <textarea className="w-full border-2 border-gray-200 rounded-lg p-3 focus:outline-none focus:border-blue-500 transition-colors" rows={3} placeholder="Write a comment..." value={commentText} onChange={(e) => setCommentText(e.target.value)}></textarea>
        {error && <p className="text-red-500 text-xs italic mb-4">{error}</p>}
        <button type="submit" className="mt-2 bg-blue-500 text-white font-semibold px-4 py-2 rounded-lg hover:bg-blue-600 transition-colors disabled:bg-blue-300" disabled={!commentText.trim()}>Post Comment</button>
      </form>
    );
  };

  const EditCommentModal = () => {
    const [newText, setNewText] = useState(commentToEdit?.text || '');
    useEffect(() => {
      if (commentToEdit) {
        setNewText(commentToEdit.text);
      }
    }, [commentToEdit]);
    const handleSubmit: FormEventHandler = async (e) => {
      e.preventDefault();
      if (newText && commentToEdit && newText !== commentToEdit.text && user) {
        // TODO
        const res = await API.updateComment(post.id, commentToEdit.id, newText, user);
        if (!res.ok) {
          alert("Failed to update comment.");
          return;
        }
        setPaginatedComments(prev => prev ? { ...prev, items: prev.items.map(c => c.id === commentToEdit.id ? {...c, text: newText} : c) } : null);
      }
      setIsEditCommentModalOpen(false)
    };
    return (
      <Modal isOpen={isEditCommentModalOpen} onClose={() => setIsEditCommentModalOpen(false)}>
        <h2 className="text-2xl font-bold mb-4">Edit Comment</h2>
        <form onSubmit={handleSubmit}>
          <div className="mb-4">
            <textarea value={newText} onChange={(e) => setNewText(e.target.value)} className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" rows={4}/>
          </div>
          <div className="flex items-center justify-end">
            <button type="submit" className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">Save Changes</button>
          </div>
        </form>
      </Modal>
    );
  };


  return (
    <RootLayout>
      <div className="p-4 md:p-6 max-w-4xl mx-auto">
        <div className="bg-white rounded-xl shadow-lg overflow-hidden">
          <img src={post.fileUrl} alt={post.title} className="w-full h-auto object-cover max-h-[75vh]" />
          <div className="p-6">
            <div className="flex flex-col sm:flex-row justify-between sm:items-start gap-4">
              <h2 className="text-3xl font-bold text-gray-800 break-words">{post.title}</h2>
              <div className="flex items-center space-x-2 flex-shrink-0">
                <a href={post.fileUrl} target="_blank" rel="noopener noreferrer">
                  <ActionButton icon={ICONS.viewRaw} className="bg-gray-200 text-gray-800">
                    Raw
                  </ActionButton>
                </a>
                {canManagePost && (
                    <>
                      <ActionButton onClick={() => onOpenEditPostModal()} icon={ICONS.edit} className="bg-yellow-500 text-white">Edit</ActionButton>
                      <ActionButton onClick={() => onPostDelete()} icon={ICONS.delete} className="bg-red-500 text-white">Delete</ActionButton>
                    </>
                )}
              </div>
            </div>
            <div className="flex flex-wrap gap-2 my-4">
              {post.tags.map(tag => (
                <span key={tag.name} className={`text-sm font-medium px-2.5 py-0.5 rounded-full ${getTagColor(tag)}`}>{tag.name}</span>
              ))}
            </div>
            <p className="text-md text-gray-600 mb-4">Posted by <span className="font-semibold">{post.author.userName}</span> &bull; {formatDate(post.createdAt)}</p>
            <p className="text-gray-700 bg-gray-50 p-4 rounded-md whitespace-pre-wrap">{post.description}</p>

            <div className="mt-6">
              <h3 className="text-xl font-semibold mb-4 text-gray-700 border-b pb-2">Comments ({paginatedComments?.totalCount ?? 0})</h3>
              <div className="space-y-4">
                {!paginatedComments ? <Loading/> : paginatedComments.items.length > 0 ? (
                  paginatedComments.items.map(comment => {
                    const canManageComment = user && (user.isAdmin || user.id === comment.author.userId);
                    return (
                      <div key={comment.id} className="bg-gray-50 p-4 rounded-lg">
                        <div className="flex justify-between items-center mb-1">
                          <p className="font-semibold text-gray-800">{comment.author.userName}</p>
                          {canManageComment && (
                            <div className="space-x-2">
                              <button onClick={() => handleOpenEditCommentModal(comment)} className="text-xs font-semibold text-yellow-600 hover:underline">Edit</button>
                              <button onClick={() => onDeleteComment(post.id, comment.id)} className="text-xs font-semibold text-red-600 hover:underline">Delete</button>
                            </div>
                          )}
                        </div>
                        <p className="text-gray-600 whitespace-pre-wrap">{comment.text}</p>
                      </div>
                    )
                  })
                ) : ( <p className="text-gray-500">No comments yet. Be the first to share your thoughts!</p> )}
              </div>
              {paginatedComments && <Pagination itemsPerPage={paginatedComments.pageSize} totalItems={paginatedComments.totalCount} paginate={setCurrentCommentPage} currentPage={currentCommentPage} />}
              {user && <CommentForm/>}
            </div>
          </div>
        </div>
      </div>
      <EditPostModal/>
      <EditCommentModal/>
    </RootLayout>
  );
}
