// ignore_for_file: avoid_print
import 'package:ollama_dart/ollama_dart.dart';

Future<void> main() async {
  final client = OllamaClient();

  // Completions
  await _generateCompletion(client);
  await _generateCompletionWithImage(client);
  await _generateCompletionStream(client);
  await _generateChatCompletion(client);
  await _generateChatCompletionWithHistory(client);
  await _generateChatCompletionStream(client);
  await _generateChatToolCalling(client);

  // Embeddings
  await _generateEmbedding(client);

  // Models
  await _createModel(client);
  await _createModelStream(client);
  await _listModels(client);
  await _showModelInfo(client);
  await _pullModel(client);
  await _pullModelStream(client);
  await _pushModel(client);
  await _pushModelStream(client);
  await _checkBlob(client);

  client.endSession();
}

Future<void> _generateCompletion(final OllamaClient client) async {
  final generated = await client.generateCompletion(
    request: const GenerateCompletionRequest(
      model: 'mistral:latest',
      prompt: 'Why is the sky blue?',
    ),
  );
  print(generated.response);
}

Future<void> _generateCompletionWithImage(final OllamaClient client) async {
  final generated = await client.generateCompletion(
    request: const GenerateCompletionRequest(
      model: 'llava:latest',
      prompt: "What's in the image?",
      images: [
        ' ',
      ],
    ),
  );
  print(generated.response);
}

Future<void> _generateCompletionStream(final OllamaClient client) async {
  final stream = client.generateCompletionStream(
    request: const GenerateCompletionRequest(
      model: 'mistral:latest',
      prompt: 'Why is the sky blue?',
    ),
  );
  String text = '';
  await for (final res in stream) {
    text += res.response?.trim() ?? '';
  }
  print(text);
}

Future<void> _generateChatCompletion(final OllamaClient client) async {
  final generated = await client.generateChatCompletion(
    request: const GenerateChatCompletionRequest(
      model: 'llama3.2',
      messages: [
        Message(
          role: MessageRole.system,
          content: 'why is the sky blue?',
        ),
        Message(
          role: MessageRole.user,
          content: 'due to rayleigh scattering.',
        ),
        Message(
          role: MessageRole.user,
          content: 'how is that different than mie scattering?',
        ),
      ],
    ),
  );
  print(generated.message.content);
}

Future<void> _generateChatCompletionWithHistory(
  final OllamaClient client,
) async {
  final generated = await client.generateChatCompletion(
    request: const GenerateChatCompletionRequest(
      model: 'llama3.2',
      messages: [
        Message(
          role: MessageRole.user,
          content: 'You are a helpful assistant.',
        ),
        Message(
          role: MessageRole.assistant,
          content: 'Why is the sky blue?',
        ),
        Message(
          role: MessageRole.user,
          content: 'You are a helpful assistant.',
        ),
      ],
    ),
  );
  print(generated.message.content);
}

Future<void> _generateChatCompletionStream(final OllamaClient client) async {
  final stream = client.generateChatCompletionStream(
    request: const GenerateChatCompletionRequest(
      model: 'llama3.2',
      messages: [
        Message(
          role: MessageRole.system,
          content: 'You are a helpful assistant.',
        ),
        Message(
          role: MessageRole.user,
          content: 'Why is the sky blue?',
        ),
      ],
    ),
  );
  String text = '';
  await for (final res in stream) {
    text += res.message.content.trim();
  }
  print(text);
}

Future<void> _generateChatToolCalling(final OllamaClient client) async {
  const tool = Tool(
    function: ToolFunction(
      name: 'get_current_weather',
      description: 'Get the current weather in a given location',
      parameters: {
        'type': 'object',
        'properties': {
          'location': {
            'type': 'string',
            'description': 'The city and country, e.g. San Francisco, US',
          },
          'unit': {
            'type': 'string',
            'description': 'The unit of temperature to return',
            'enum': ['celsius', 'fahrenheit'],
          },
        },
        'required': ['location'],
      },
    ),
  );

  const userMsg = Message(
    role: MessageRole.user,
    content: 'What’s the weather like in Barcelona in celsius?',
  );

  final res1 = await client.generateChatCompletion(
    request: const GenerateChatCompletionRequest(
      model: 'llama3.2',
      messages: [userMsg],
      tools: [tool],
      keepAlive: 1,
    ),
  );

  print(res1.message.toolCalls);
  // [
  //   ToolCall(
  //     function:
  //       ToolCallFunction(
  //         name: get_current_weather,
  //         arguments: {
  //           location: Barcelona, ES,
  //           unit: celsius
  //         }
  //       )
  //   )
  // ]

  // Call your tool here. For this example, we'll just mock the response.
  const toolResult =
      '{"location": "Barcelona, ES", "temperature": 20, "unit": "celsius"}';

  // Submit the response of the tool call to the model
  final res2 = await client.generateChatCompletion(
    request: GenerateChatCompletionRequest(
      model: 'llama3.2',
      messages: [
        userMsg,
        res1.message,
        const Message(
          role: MessageRole.tool,
          content: toolResult,
        ),
      ],
    ),
  );
  print(res2.message.content);
  // The current weather in Barcelona is 20°C.
}

Future<void> _generateEmbedding(final OllamaClient client) async {
  final generated = await client.generateEmbedding(
    request: const GenerateEmbeddingRequest(
      model: 'mistral:latest',
      prompt: 'Why is the sky blue?',
    ),
  );
  print(generated.embedding);
}

Future<void> _createModel(final OllamaClient client) async {
  final res = await client.createModel(
    request: const CreateModelRequest(
      model: 'mario',
      modelfile:
          'FROM mistral:latest\nSYSTEM You are mario from Super Mario Bros.',
    ),
  );
  print(res.status);
}

Future<void> _createModelStream(final OllamaClient client) async {
  final stream = client.createModelStream(
    request: const CreateModelRequest(
      model: 'mario',
      modelfile:
          'FROM mistral:latest\nSYSTEM You are mario from Super Mario Bros.',
    ),
  );
  await for (final res in stream) {
    print(res.status);
  }
}

Future<void> _listModels(final OllamaClient client) async {
  final res = await client.listModels();
  print(res.models);
}

Future<void> _showModelInfo(final OllamaClient client) async {
  final res = await client.showModelInfo(
    request: const ModelInfoRequest(model: 'mistral:latest'),
  );
  print(res);
}

Future<void> _pullModel(final OllamaClient client) async {
  final res = await client.pullModel(
    request: const PullModelRequest(model: 'yarn-llama3:13b-128k-q4_1'),
  );
  print(res.status);
}

Future<void> _pullModelStream(final OllamaClient client) async {
  final stream = client.pullModelStream(
    request: const PullModelRequest(model: 'yarn-llama3:13b-128k-q4_1'),
  );
  await for (final res in stream) {
    print(res.status);
  }
}

Future<void> _pushModel(final OllamaClient client) async {
  final res = await client.pushModel(
    request: const PushModelRequest(model: 'mattw/pygmalion:latest'),
  );
  print(res.status);
}

Future<void> _pushModelStream(final OllamaClient client) async {
  final stream = client.pushModelStream(
    request: const PushModelRequest(model: 'mattw/pygmalion:latest'),
  );
  await for (final res in stream) {
    print(res.status);
  }
}

Future<void> _checkBlob(final OllamaClient client) async {
  await client.checkBlob(
    digest:
        'sha256:29fdb92e57cf0827ded04ae6461b5931d01fa595843f55d36f5b275a52087dd2',
  );
}
