import logging
import requests
from django.template.loader import render_to_string

from fellchensammlung.models import SocialMediaPost, PlatformChoices
from notfellchen import settings


class FediClient:
    def __init__(self, access_token, api_base_url):
        """
        :param access_token: Your server API access token.
        :param api_base_url: The base URL of the Fediverse instance (e.g., 'https://gay-pirate-assassins.de').
        """
        self.access_token = access_token
        self.api_base_url = api_base_url.rstrip('/')
        self.headers = {
            'Authorization': f'Bearer {self.access_token}',
        }

    def upload_media(self, image_path, alt_text):
        """
        Uploads media (image) to the server and returns the media ID.
        :param image_path: Path to the image file to upload.
        :param alt_text: Description (alt text) for the image.
        :return: The media ID of the uploaded image.
        """

        media_endpoint = f'{self.api_base_url}/api/v2/media'

        with open(image_path, 'rb') as image_file:
            files = {
                'file': image_file,
                'description': (None, alt_text)
            }
            response = requests.post(media_endpoint, headers=self.headers, files=files)

            # Raise exception if upload fails
            response.raise_for_status()

        # Parse and return the media ID from the response
        media_id = response.json().get('id')
        return media_id

    def post_status(self, status, media_ids=None):
        """
        Posts a status to Mastodon with optional media.
        :param status: The text of the status to post.
        :param media_ids: A list of media IDs to attach to the status (optional).
        :return: The response from the Mastodon API.
        """
        status_endpoint = f'{self.api_base_url}/api/v1/statuses'

        payload = {
            'status': status,
            'media_ids[]': media_ids if media_ids else []
        }
        response = requests.post(status_endpoint, headers=self.headers, data=payload)

        # Raise exception if posting fails
        if response.status_code >= 300:
            logging.error(f"Request= {response.request.body}")
            logging.error(f"Response= {response.json()}")
        response.raise_for_status()

        return response.json()

    def post_status_with_images(self, status, images):
        """
        Uploads one or more image, then posts a status with that images and alt text.
        :param status: The text of the status.
        :param image_paths: The paths to the image file.
        :param alt_text: The alt text for the image.
        :return: The response from the Mastodon API.
        """
        MAX_NUM_OF_IMAGES = 6
        if len(images) > MAX_NUM_OF_IMAGES:
            logging.warning(f"Too many images ({len(images)}) to post. Selecting the first {MAX_NUM_OF_IMAGES} images.")
        media_ids = []
        for image in images[:MAX_NUM_OF_IMAGES]:
            # Upload the image and get the media ID
            media_ids.append(self.upload_media(f"{settings.MEDIA_ROOT}/{image.image}", image.alt_text))

        # Post the status with the uploaded image's media ID
        return self.post_status(status, media_ids=media_ids)


def post_an_to_fedi(adoption_notice):
    client = FediClient(settings.fediverse_access_token, settings.fediverse_api_base_url)

    context = {"adoption_notice": adoption_notice}
    status_text = render_to_string("fellchensammlung/misc/fediverse/an-post.md", context)
    images = adoption_notice.get_photos()

    if images is not None:
        response = client.post_status_with_images(status_text, images)
    else:
        response = client.post_status(status_text)
    logging.info(response)
    post = SocialMediaPost.objects.create(adoption_notice=adoption_notice,
                                          platform=PlatformChoices.FEDIVERSE,
                                          url=response['url'], )
    return post
