import requests
from orshot.constants import (
    ORSHOT_SOURCE,
    ORSHOT_API_VERSION,
    ORSHOT_API_BASE_URL,
    DEFAULT_RENDER_TYPE,
    DEFAULT_RESPONSE_TYPE,
    DEFAULT_RESPONSE_FORMAT
)
from orshot.types import RenderOptions, SignedUrlOptions, StudioRenderOptions
from orshot.exceptions import APIException, BadRequestException

class Orshot:
    def __init__(self, api_key: str):
        self.api_key = api_key

    def _get_base_url(self):
        return f"{ORSHOT_API_BASE_URL}/{ORSHOT_API_VERSION}"
    
    def _get_headers(self):
        return {
            'Content-Type': 'application/json',
            'Authorization': f'Bearer {self.api_key}'
        }

    def render_from_template(self, render_options: RenderOptions):
        template_id = render_options.get('template_id')
        modifications = render_options.get('modifications')
        response_type = render_options.get('response_type', DEFAULT_RESPONSE_TYPE)
        response_format = render_options.get('response_format', DEFAULT_RESPONSE_FORMAT)

        endpoint_url = f"{self._get_base_url()}/generate/images/{template_id}"

        data = {
            'source': ORSHOT_SOURCE,
            'modifications': modifications,
            'response': {
                'type': response_type,
                'format': response_format
            }
        }

        response = requests.post(endpoint_url, headers=self._get_headers(), json=data)

        if response.status_code == 200:
            if response_type == "base64" or response_type == "url":
                return response.json()
            else:
                return response
        elif response.status_code == 400:
            error_response = response.json().get('error')

            raise BadRequestException(error_response)
        else:
            raise APIException(f"An error occurred while generating an image. Status code: {response.status_code}. Error: {response.json().get('error')}")

    def generate_signed_url(self, signed_url_options: SignedUrlOptions):
        endpoint_url = f"{self._get_base_url()}/signed-url/create"

        data = {
            'source': ORSHOT_SOURCE,
            'templateId': signed_url_options.get('template_id'),
            'modifications': signed_url_options.get('modifications'),
            'responseFormat': signed_url_options.get('response_format', DEFAULT_RESPONSE_FORMAT),
            'renderType': signed_url_options.get('render_type', DEFAULT_RENDER_TYPE),
            'expiresAt': signed_url_options.get('expires_at')
        }

        response = requests.post(endpoint_url, headers=self._get_headers(), json=data)

        if response.status_code == 200:
            return response.json()
        else:
            raise APIException(f"An error occurred while generating a signed URL. Status code: {response.status_code}. Error: {response.json()}")

    def render_from_studio_template(self, options: StudioRenderOptions):
        template_id = options.get('template_id')
        modifications = options.get('modifications')
        response_opts = options.get('response', {})
        pdf_options = options.get('pdf_options')
        video_options = options.get('video_options')
        publish = options.get('publish')

        response_type = response_opts.get('type', DEFAULT_RESPONSE_TYPE)
        response_format = response_opts.get('format', DEFAULT_RESPONSE_FORMAT)

        endpoint_url = f"{self._get_base_url()}/studio/render"

        data = {
            'templateId': template_id,
            'source': ORSHOT_SOURCE,
            'response': {
                'type': response_type,
                'format': response_format,
            }
        }

        if modifications:
            data['modifications'] = modifications

        if response_opts.get('scale') is not None:
            data['response']['scale'] = response_opts['scale']

        if response_opts.get('include_pages'):
            data['response']['includePages'] = response_opts['include_pages']

        if response_opts.get('file_name'):
            data['response']['fileName'] = response_opts['file_name']

        if pdf_options:
            data['pdfOptions'] = {}
            if pdf_options.get('margin') is not None:
                data['pdfOptions']['margin'] = pdf_options['margin']
            if pdf_options.get('range_from') is not None:
                data['pdfOptions']['rangeFrom'] = pdf_options['range_from']
            if pdf_options.get('range_to') is not None:
                data['pdfOptions']['rangeTo'] = pdf_options['range_to']
            if pdf_options.get('color_mode') is not None:
                data['pdfOptions']['colorMode'] = pdf_options['color_mode']
            if pdf_options.get('dpi') is not None:
                data['pdfOptions']['dpi'] = pdf_options['dpi']

        if video_options:
            data['videoOptions'] = {}
            if video_options.get('trim_start') is not None:
                data['videoOptions']['trimStart'] = video_options['trim_start']
            if video_options.get('trim_end') is not None:
                data['videoOptions']['trimEnd'] = video_options['trim_end']
            if video_options.get('muted') is not None:
                data['videoOptions']['muted'] = video_options['muted']
            if video_options.get('loop') is not None:
                data['videoOptions']['loop'] = video_options['loop']

        if publish:
            data['publish'] = {
                'accounts': publish['accounts'],
            }
            if publish.get('content') is not None:
                data['publish']['content'] = publish['content']
            if publish.get('is_draft') is not None:
                data['publish']['isDraft'] = publish['is_draft']
            if publish.get('timezone') is not None:
                data['publish']['timezone'] = publish['timezone']
            if publish.get('platform_options') is not None:
                data['publish']['platformOptions'] = publish['platform_options']
            if publish.get('schedule'):
                data['publish']['schedule'] = {}
                if publish['schedule'].get('scheduled_for'):
                    data['publish']['schedule']['scheduledFor'] = publish['schedule']['scheduled_for']

        response = requests.post(endpoint_url, headers=self._get_headers(), json=data)

        if response.status_code == 200:
            if response_type in ('base64', 'url'):
                return response.json()
            else:
                return response
        elif response.status_code == 400:
            error_response = response.json().get('error')
            raise BadRequestException(error_response)
        else:
            raise APIException(f"An error occurred while rendering studio template. Status code: {response.status_code}. Error: {response.json().get('error')}")
