import json
from unittest.mock import patch, MagicMock

from src.fetcher import fetch_and_cache_articles
from src.models import Article, Image
from conftest import SAMPLE_RSS_XML


def _mock_feed_response(xml_content):
    mock = MagicMock()
    mock.content = xml_content.encode("utf-8")
    mock.text = xml_content
    mock.status_code = 200
    mock.raise_for_status = MagicMock()
    return mock


def test_fetch_creates_articles(app, db):
    with app.app_context():
        with patch("src.fetcher.requests.get") as mock_get:
            mock_get.return_value = _mock_feed_response(SAMPLE_RSS_XML)
            with patch("src.fetcher.process_image") as mock_img:
                mock_img.return_value = ("/fake/path.jpg", 800, 450)
                result = fetch_and_cache_articles()

        assert result["new"] == 2
        assert result["skipped"] == 0
        articles = Article.query.order_by(Article.pub_date).all()
        assert len(articles) == 2
        assert articles[0].title == "Test Article One"
        assert articles[1].title == "Test Article Two"


def test_fetch_deduplicates(app, db):
    with app.app_context():
        with patch("src.fetcher.requests.get") as mock_get:
            mock_get.return_value = _mock_feed_response(SAMPLE_RSS_XML)
            with patch("src.fetcher.process_image") as mock_img:
                mock_img.return_value = ("/fake/path.jpg", 800, 450)
                fetch_and_cache_articles()
                result = fetch_and_cache_articles()

        assert result["new"] == 0
        assert result["skipped"] == 2
        assert Article.query.count() == 2


def test_fetch_downloads_images(app, db):
    with app.app_context():
        with patch("src.fetcher.requests.get") as mock_get:
            mock_get.return_value = _mock_feed_response(SAMPLE_RSS_XML)
            with patch("src.fetcher.process_image") as mock_img:
                mock_img.return_value = ("/fake/path.jpg", 800, 450)
                fetch_and_cache_articles()

        images = Image.query.all()
        assert len(images) == 1
        assert images[0].original_url == "https://example.com/image1.jpg"


def test_fetch_rewrites_image_src(app, db):
    with app.app_context():
        with patch("src.fetcher.requests.get") as mock_get:
            mock_get.return_value = _mock_feed_response(SAMPLE_RSS_XML)
            with patch("src.fetcher.process_image") as mock_img:
                mock_img.return_value = ("/fake/path.jpg", 800, 450)
                fetch_and_cache_articles()

        article = Article.query.filter_by(
            guid="https://example.com/?p=1001"
        ).first()
        assert "https://example.com/image1.jpg" not in article.content_html
        assert "/fake/path.jpg" in article.content_html


def test_fetch_handles_feed_error(app, db):
    with app.app_context():
        with patch("src.fetcher.requests.get") as mock_get:
            mock_get.side_effect = Exception("Network error")
            result = fetch_and_cache_articles()

        assert result["error"] is not None
        assert Article.query.count() == 0


def test_fetch_converts_timezone_to_eastern(app, db):
    with app.app_context():
        with patch("src.fetcher.requests.get") as mock_get:
            mock_get.return_value = _mock_feed_response(SAMPLE_RSS_XML)
            with patch("src.fetcher.process_image") as mock_img:
                mock_img.return_value = ("/fake/path.jpg", 800, 450)
                fetch_and_cache_articles()

        article = Article.query.filter_by(title="Test Article One").first()
        # The XML has: Mon, 06 Apr 2026 12:00:00 +0000
        # US/Eastern in April is EDT (UTC-4), so it should be 08:00:00
        assert article.pub_date.tzinfo is None
        assert article.pub_date.hour == 8
        assert article.pub_date.minute == 0
