# Copyright (c) ModelScope Contributors. All rights reserved.
import os
from typing import List

from swift.arguments import ExportArguments
from swift.infer_engine import RequestConfig, TransformersEngine
from swift.template import Template
from swift.utils import get_logger
from ..utils import prepare_model_template

logger = get_logger()


def replace_and_concat(template: 'Template', template_list: List, placeholder: str, keyword: str):
    final_str = ''
    for t in template_list:
        if isinstance(t, str):
            final_str += t.replace(placeholder, keyword)
        elif isinstance(t, (tuple, list)):
            if isinstance(t[0], int):
                final_str += template.tokenizer.decode(t)
            else:
                for attr in t:
                    if attr == 'bos_token_id':
                        final_str += template.tokenizer.bos_token
                    elif attr == 'eos_token_id':
                        final_str += template.tokenizer.eos_token
                    else:
                        raise ValueError(f'Unknown token: {attr}')
    return final_str


def export_to_ollama(args: ExportArguments):
    args.device_map = 'meta'  # Accelerate load speed.
    logger.info('Exporting to ollama:')
    os.makedirs(args.output_dir, exist_ok=True)
    model, template = prepare_model_template(args)
    engine = TransformersEngine(model, template=template)
    logger.info(f'Using model_dir: {engine.model_dir}')
    template_meta = template.template_meta
    with open(os.path.join(args.output_dir, 'Modelfile'), 'w', encoding='utf-8') as f:
        f.write(f'FROM {engine.model_dir}\n')
        f.write(f'TEMPLATE """{{{{ if .System }}}}'
                f'{replace_and_concat(template, template_meta.system_prefix, "{{SYSTEM}}", "{{ .System }}")}'
                f'{{{{ else }}}}{replace_and_concat(template, template_meta.prefix, "", "")}'
                f'{{{{ end }}}}')
        f.write(f'{{{{ if .Prompt }}}}'
                f'{replace_and_concat(template, template_meta.prompt, "{{QUERY}}", "{{ .Prompt }}")}'
                f'{{{{ end }}}}')
        f.write('{{ .Response }}')
        f.write(replace_and_concat(template, template_meta.suffix, '', '') + '"""\n')
        f.write(f'PARAMETER stop "{replace_and_concat(template, template_meta.suffix, "", "")}"\n')

        request_config = RequestConfig(
            temperature=args.temperature,
            top_k=args.top_k,
            top_p=args.top_p,
            repetition_penalty=args.repetition_penalty)
        generation_config = engine._prepare_generation_config(request_config)
        engine._add_stop_words(generation_config, request_config)
        for stop_word in generation_config.stop_words:
            f.write(f'PARAMETER stop "{stop_word}"\n')
        f.write(f'PARAMETER temperature {generation_config.temperature}\n')
        f.write(f'PARAMETER top_k {generation_config.top_k}\n')
        f.write(f'PARAMETER top_p {generation_config.top_p}\n')
        f.write(f'PARAMETER repeat_penalty {generation_config.repetition_penalty}\n')

    logger.info('Save Modelfile done, you can start ollama by:')
    logger.info('> ollama serve')
    logger.info('In another terminal:')
    logger.info('> ollama create my-custom-model '
                f'-f {os.path.join(args.output_dir, "Modelfile")}')
    logger.info('> ollama run my-custom-model')
