#!/usr/bin/env perl
# Generate pre-computed OpenAPI operation lookup modules from YAML specs.
# Usage: perl maint/generate_spec_data.pl
#
# Reads share/*.yaml and writes lib/Langertha/Spec/*.pm with the
# server_url and all operationId → (method, path, content_type) mappings.

use strict;
use warnings;
use FindBin;
use File::Spec;
use YAML::PP;
use JSON::PP ();

my $base = File::Spec->catdir($FindBin::Bin, '..');
my $share_dir = File::Spec->catdir($base, 'share');
my $spec_dir  = File::Spec->catdir($base, 'lib', 'Langertha', 'Spec');

unless (-d $spec_dir) {
  mkdir $spec_dir or die "Cannot create $spec_dir: $!";
}

my $yp = YAML::PP->new(boolean => 'JSON::PP');

my @specs = (
  { yaml => 'openai.yaml',  module => 'OpenAI',  abstract => 'Pre-computed OpenAPI operations for OpenAI' },
  { yaml => 'mistral.yaml', module => 'Mistral', abstract => 'Pre-computed OpenAPI operations for Mistral' },
  { yaml => 'ollama.yaml',  module => 'Ollama',  abstract => 'Pre-computed OpenAPI operations for Ollama' },
  { yaml => 'lmstudio.yaml', module => 'LMStudio', abstract => 'Pre-computed OpenAPI operations for LM Studio native API' },
);

for my $spec (@specs) {
  my $yaml_file = File::Spec->catfile($share_dir, $spec->{yaml});
  die "YAML file not found: $yaml_file\n" unless -f $yaml_file;

  print "Parsing $spec->{yaml}...\n";
  my $data = $yp->load_file($yaml_file);

  my $server_url = $data->{servers}[0]{url} if $data->{servers} && @{$data->{servers}};

  my %operations;
  my $paths = $data->{paths} || {};
  for my $path (sort keys %$paths) {
    for my $method (sort keys %{$paths->{$path}}) {
      next unless ref $paths->{$path}{$method} eq 'HASH';
      my $op = $paths->{$path}{$method};
      my $opId = $op->{operationId} or next;
      my $ct;
      if ($op->{requestBody} && $op->{requestBody}{content}) {
        $ct = 'application/json' if $op->{requestBody}{content}{'application/json'};
        $ct //= 'multipart/form-data' if $op->{requestBody}{content}{'multipart/form-data'};
      }
      $operations{$opId} = {
        method       => uc($method),
        path         => $path,
        defined $ct ? (content_type => $ct) : (),
      };
    }
  }

  my $op_count = scalar keys %operations;
  print "  Found $op_count operations, server_url=$server_url\n";

  # Generate Perl source
  my $ops_code = _render_operations(\%operations);

  my $pm_file = File::Spec->catfile($spec_dir, "$spec->{module}.pm");

  my $source = <<"END_PM";
package Langertha::Spec::$spec->{module};
# ABSTRACT: $spec->{abstract}
our \$VERSION = '0.203';

# AUTO-GENERATED by maint/generate_spec_data.pl -- do not edit manually.
# Source: share/$spec->{yaml} ($op_count operations)

my \$DATA;

sub data {
  \$DATA //= {
    server_url => '$server_url',
    operations => {
$ops_code
    },
  };
  return \$DATA;
}

1;
END_PM

  open my $fh, '>:encoding(UTF-8)', $pm_file or die "Cannot write $pm_file: $!";
  print $fh $source;
  close $fh;
  print "  Wrote $pm_file\n";
}

print "Done.\n";

sub _render_operations {
  my ($ops) = @_;
  my @lines;
  for my $id (sort keys %$ops) {
    my $op = $ops->{$id};
    my @fields;
    push @fields, sprintf("method => '%s'", $op->{method});
    push @fields, sprintf("path => '%s'", $op->{path});
    push @fields, sprintf("content_type => '%s'", $op->{content_type}) if $op->{content_type};
    push @lines, "      '$id' => { " . join(', ', @fields) . " },";
  }
  return join("\n", @lines);
}
