import React, { createContext, useState, useContext, useEffect } from "react";
import { api } from "../utils/api";
import {
  ArticleModel,
  ArticlesModel,
  createArticlesModelObject,
} from "../types/models";
import { ArticleContextModel } from "../types/contexts";
import { useAuth } from "./Author";

const ArticleContext = createContext<ArticleContextModel | undefined>(undefined);

export const ArticleProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const [articles, setArticles] = useState<ArticlesModel>(createArticlesModelObject());
  const [loading, setLoading] = useState<boolean>(true);
  const [error, setError] = useState<string | null>(null);
  const { currentUser } = useAuth();

  /** 🔹 Author IDs must be strings for API, so we normalize here */
  const normalizeArticleForApi = (article: Partial<ArticleModel>) => {
    // Extract existing authors as a list of IDs (string[])
    const existingIds = (article.authors ?? []).map(a =>
      typeof a === "string" ? a : a._id
    );

    // Inject currentUser if missing
    const allAuthorIds = currentUser?._id
      ? Array.from(new Set([...existingIds, currentUser._id])) // dedupe
      : existingIds;

    return {
      ...article,
      authors: allAuthorIds,
    };
  };

  /** 🔹 Fetch articles (JWT automatically attached by api.ts interceptor) */
  const fetchArticles = async () => {
    try {
      setLoading(true);
      setError(null);

      const res = await api.get<ArticleModel[]>('/articles', { params: { skip: 0, limit: 100 } });
      const formatted = res.data.map((a) => ({ ...a, id: a._id || undefined }));
      setArticles(prev => prev.refresh(formatted));
    } catch (err: any) {
      console.error('Failed to fetch articles:', err);
      setError(err.response?.data?.detail || 'Failed to fetch articles');
    } finally {
      setLoading(false);
    }
  };

  /** 🔹 Update article */
  const updateArticle = async (articleData: ArticleModel) => {
    if (!articleData._id) {
      console.error('updateArticle called without _id');
      return;
    }
    if (!currentUser) {
      console.error('updateArticle called without logged in user');
      return;
    }

    const normalizedArticleData = normalizeArticleForApi(articleData);
    try {
      setLoading(true);
      setError(null);

      const res = await api.put<ArticleModel>(`/articles/${articleData._id}`, normalizedArticleData);
      setArticles(prev => {
        prev.update(res.data);
        return { ...prev };
      });
      return res.data;
    } catch (err: any) {
      console.error('Article update failed:', err);
      setError(err.response?.data?.detail || 'Failed to update article');
    } finally {
      setLoading(false);
    }
  };

  /** 🔹 Create article */
  const createArticle = async (articleData: ArticleModel) => {
    if (articleData._id) {
      console.error('createArticle called with _id');
      return;
    }

    const normalizedArticleData = normalizeArticleForApi(articleData);
    try {
      setLoading(true);
      setError(null);

      const res = await api.post<ArticleModel>(`/articles`, normalizedArticleData);
      setArticles(prev => {
        prev.create(res.data);
        return { ...prev };
      });
      return res.data;
    } catch (err: any) {
      console.error('Article create failed:', err);
      setError(err.response?.data?.detail || 'Failed to create article');
    } finally {
      setLoading(false);
    }
  };

  /** 🔹 Auto-fetch articles whenever user logs in/out */
  useEffect(() => {
    fetchArticles();
  }, [currentUser]); // refetch on login / logout

  return (
    <ArticleContext.Provider value={{
      articles,
      loading,
      error,
      refreshArticles: fetchArticles,
      updateArticle,
      createArticle,
    }}>
      {children}
    </ArticleContext.Provider>
  );
};

export const useArticles = (): ArticleContextModel => {
  const ctx = useContext(ArticleContext);
  if (!ctx) throw new Error('useArticles must be used inside ArticleProvider');
  return ctx;
};
