# Copyright (c) ModelScope Contributors. All rights reserved.
from typing import Any, Dict, List, Literal

from ..base import Template
from ..constant import MLLMTemplateType
from ..register import register_template
from ..template_inputs import StdTemplateInputs
from ..utils import Context, findall
from .utils import TemplateMeta


class DotsOCRTemplate(Template):
    image_token_id = 151665
    placeholder_tokens = ['<|imgpad|>']

    def replace_tag(self, media_type: Literal['image', 'video', 'audio'], index: int,
                    inputs: StdTemplateInputs) -> List[Context]:
        from qwen_vl_utils import fetch_image
        assert media_type == 'image'
        inputs.images[index] = fetch_image({'image': inputs.images[index]})
        if self.mode == 'lmdeploy':
            return ['<|img|>', [-100], '<|endofimg|>']
        else:
            return ['<|img|><|imgpad|><|endofimg|>']

    def _encode(self, inputs: StdTemplateInputs) -> Dict[str, Any]:
        encoded = super()._encode(inputs)
        processor = self.processor
        input_ids = encoded['input_ids']
        labels = encoded['labels']
        loss_scale = encoded.get('loss_scale', None)

        images = inputs.images
        media_token = self.image_token_id
        media_inputs = processor.image_processor(images=images, videos=None, return_tensors='pt', do_resize=False)
        media_grid_thw = media_inputs['image_grid_thw']
        idx_list = findall(input_ids, media_token)
        merge_length = processor.image_processor.merge_size**2

        def _get_new_tokens(i):
            token_len = (media_grid_thw[i].prod() // merge_length)
            return [media_token] * token_len

        input_ids, labels, loss_scale = self._extend_tokens(input_ids, labels, loss_scale, idx_list, _get_new_tokens)
        encoded.update(media_inputs)

        encoded['input_ids'] = input_ids
        encoded['labels'] = labels
        encoded['loss_scale'] = loss_scale
        return encoded


register_template(
    TemplateMeta(
        MLLMTemplateType.dots_ocr,
        prefix=[''],
        prompt=['<|user|>{{QUERY}}<|endofuser|><|assistant|>'],
        chat_sep=['<|endofassistant|>'],
        suffix=['<|endofassistant|>'],
        system_prefix=['<|system|>{{SYSTEM}}<|endofsystem|>\n'],
        template_cls=DotsOCRTemplate,
    ))
