import fs from 'node:fs';
import path from 'node:path';
import { z } from 'zod';
import { config } from '../../config.js';
import { detectProject } from '../../lib/frameworks/detect.js';
import { kebabCase, pascalCase, camelCase } from '../../lib/strings.js';
import { resolveWorkspacePath } from '../../lib/sandbox.js';
import { errorResult, jsonResult, toErrorMessage } from '../shared.js';
function pluralize(word) {
    const lower = word.toLowerCase();
    if (lower.endsWith('ies'))
        return word;
    if (lower.endsWith('y') && !/[aeiou]y$/i.test(word))
        return `${word.slice(0, -1)}ies`;
    if (/(s|x|z|ch|sh)$/i.test(word))
        return `${word}es`;
    if (lower.endsWith('s'))
        return word;
    return `${word}s`;
}
function requireDjango() {
    const detected = detectProject(config.workspaceRoot);
    if (detected.backend?.kind !== 'django') {
        throw new Error('No Django project detected. Expected manage.py or a Django dependency file.');
    }
    return detected.backend;
}
function assertWritable(file, overwrite) {
    if (!overwrite && fs.existsSync(file)) {
        throw new Error(`"${file}" already exists. Pass overwrite: true to replace it.`);
    }
}
export function registerGenerateDjangoResourceTool(server) {
    server.registerTool('generate_django_resource', {
        title: 'Generate Django Resource',
        description: 'Scaffold a Django app resource: models.py model class, views (APIView-style stubs), urls.py, and admin registration. ' +
            'Writes files under the given app directory (created if missing). Does not run migrate.',
        inputSchema: {
            name: z.string().min(1).describe('Resource/model name, e.g. "Post" or "blog_post".'),
            app: z
                .string()
                .optional()
                .describe('Django app directory relative to the project root. Defaults to a kebab-case plural of the name.'),
            overwrite: z.boolean().optional().default(false),
        },
    }, async ({ name, app, overwrite }) => {
        try {
            const django = requireDjango();
            const model = pascalCase(name);
            const appName = app?.trim() || kebabCase(pluralize(model)).replace(/-/g, '_');
            const appDir = resolveWorkspacePath(django.root, appName);
            fs.mkdirSync(appDir, { recursive: true });
            const files = [];
            const modelFile = path.join(appDir, 'models.py');
            const viewsFile = path.join(appDir, 'views.py');
            const urlsFile = path.join(appDir, 'urls.py');
            const adminFile = path.join(appDir, 'admin.py');
            const appsFile = path.join(appDir, 'apps.py');
            const initFile = path.join(appDir, '__init__.py');
            for (const file of [modelFile, viewsFile, urlsFile, adminFile, appsFile]) {
                assertWritable(file, overwrite ?? false);
            }
            if (!fs.existsSync(initFile)) {
                fs.writeFileSync(initFile, '');
                files.push(initFile);
            }
            fs.writeFileSync(modelFile, `from django.db import models


class ${model}(models.Model):
    title = models.CharField(max_length=255)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self) -> str:
        return self.title
`);
            files.push(modelFile);
            fs.writeFileSync(viewsFile, `from django.http import JsonResponse
from django.views import View

from .models import ${model}


class ${model}ListView(View):
    def get(self, request):
        items = list(${model}.objects.values("id", "title", "created_at"))
        return JsonResponse({"results": items})
`);
            files.push(viewsFile);
            const routeName = kebabCase(pluralize(model));
            fs.writeFileSync(urlsFile, `from django.urls import path

from .views import ${model}ListView

urlpatterns = [
    path("${routeName}/", ${model}ListView.as_view(), name="${routeName}-list"),
]
`);
            files.push(urlsFile);
            fs.writeFileSync(adminFile, `from django.contrib import admin

from .models import ${model}

admin.site.register(${model})
`);
            files.push(adminFile);
            fs.writeFileSync(appsFile, `from django.apps import AppConfig


class ${pascalCase(appName)}Config(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "${appName}"
`);
            files.push(appsFile);
            return jsonResult({
                kind: 'django',
                model,
                app: appName,
                route: `/${routeName}/`,
                files,
                nextSteps: [
                    `Add "${appName}" to INSTALLED_APPS.`,
                    `Include path("${appName}/", include("${appName}.urls")) in the project urls.py.`,
                    'Run python manage.py makemigrations && python manage.py migrate.',
                ],
            });
        }
        catch (error) {
            return errorResult(toErrorMessage(error));
        }
    });
}
export function registerGenerateRailsResourceTool(server) {
    server.registerTool('generate_rails_resource', {
        title: 'Generate Rails Resource',
        description: 'Scaffold Rails model + controller stubs and append a resources route hint to config/routes.rb when present. ' +
            'File-based (does not invoke `rails generate`).',
        inputSchema: {
            name: z.string().min(1).describe('Resource name, e.g. "Post" or "blog_post".'),
            api: z.boolean().optional().default(true).describe('If true, generate an API-style controller under app/controllers/api.'),
            overwrite: z.boolean().optional().default(false),
        },
    }, async ({ name, api, overwrite }) => {
        try {
            const detected = detectProject(config.workspaceRoot);
            if (detected.backend?.kind !== 'rails') {
                return errorResult('No Rails project detected. Expected a Gemfile with rails and/or bin/rails.');
            }
            const root = detected.backend.root;
            const model = pascalCase(name);
            const plural = pluralize(model);
            const controllerName = `${plural}Controller`;
            const table = kebabCase(plural).replace(/-/g, '_');
            const modelFile = resolveWorkspacePath(root, path.join('app', 'models', `${kebabCase(model).replace(/-/g, '_')}.rb`));
            const controllerRel = api
                ? path.join('app', 'controllers', 'api', `${kebabCase(plural).replace(/-/g, '_')}_controller.rb`)
                : path.join('app', 'controllers', `${kebabCase(plural).replace(/-/g, '_')}_controller.rb`);
            const controllerFile = resolveWorkspacePath(root, controllerRel);
            assertWritable(modelFile, overwrite ?? false);
            assertWritable(controllerFile, overwrite ?? false);
            fs.mkdirSync(path.dirname(modelFile), { recursive: true });
            fs.mkdirSync(path.dirname(controllerFile), { recursive: true });
            const files = [];
            fs.writeFileSync(modelFile, `class ${model} < ApplicationRecord
  # self.table_name = "${table}"
end
`);
            files.push(modelFile);
            const parent = api ? 'ApplicationController' : 'ApplicationController';
            fs.writeFileSync(controllerFile, api
                ? `module Api
  class ${controllerName} < ${parent}
    def index
      render json: ${model}.all
    end

    def show
      render json: ${model}.find(params[:id])
    end
  end
end
`
                : `class ${controllerName} < ${parent}
  def index
    @${camelCase(plural)} = ${model}.all
  end

  def show
    @${camelCase(model)} = ${model}.find(params[:id])
  end
end
`);
            files.push(controllerFile);
            const routesFile = path.join(root, 'config', 'routes.rb');
            let routeWired = false;
            const routeLine = api
                ? `  namespace :api do\n    resources :${table}, only: %i[index show]\n  end`
                : `  resources :${table}, only: %i[index show]`;
            if (fs.existsSync(routesFile)) {
                const text = fs.readFileSync(routesFile, 'utf8');
                if (!text.includes(`resources :${table}`)) {
                    const wired = text.includes('Rails.application.routes.draw')
                        ? text.replace(/Rails\.application\.routes\.draw do\s*\n/, (match) => `${match}${routeLine}\n`)
                        : `${text.trimEnd()}\n${routeLine}\n`;
                    fs.writeFileSync(routesFile, wired);
                    routeWired = true;
                    files.push(routesFile);
                }
            }
            return jsonResult({
                kind: 'rails',
                model,
                controller: controllerName,
                api: Boolean(api),
                route: api ? `/api/${table}` : `/${table}`,
                routeWired,
                files,
                nextSteps: [
                    'Add a migration for the model (bin/rails g migration Create...).',
                    routeWired ? 'Review config/routes.rb for the new resources entry.' : 'Add a resources route in config/routes.rb.',
                ],
            });
        }
        catch (error) {
            return errorResult(toErrorMessage(error));
        }
    });
}
export function registerGenerateSymfonyResourceTool(server) {
    server.registerTool('generate_symfony_resource', {
        title: 'Generate Symfony Resource',
        description: 'Scaffold a Symfony Entity + Repository + Controller stub under src/. File-based (does not invoke MakerBundle).',
        inputSchema: {
            name: z.string().min(1).describe('Resource/entity name, e.g. "Post" or "blog_post".'),
            overwrite: z.boolean().optional().default(false),
        },
    }, async ({ name, overwrite }) => {
        try {
            const detected = detectProject(config.workspaceRoot);
            if (detected.backend?.kind !== 'symfony') {
                return errorResult('No Symfony project detected. Expected symfony/framework-bundle or bin/console.');
            }
            const root = detected.backend.root;
            const entity = pascalCase(name);
            const route = kebabCase(pluralize(entity));
            const entityFile = resolveWorkspacePath(root, path.join('src', 'Entity', `${entity}.php`));
            const repoFile = resolveWorkspacePath(root, path.join('src', 'Repository', `${entity}Repository.php`));
            const controllerFile = resolveWorkspacePath(root, path.join('src', 'Controller', `${entity}Controller.php`));
            for (const file of [entityFile, repoFile, controllerFile]) {
                assertWritable(file, overwrite ?? false);
                fs.mkdirSync(path.dirname(file), { recursive: true });
            }
            fs.writeFileSync(entityFile, `<?php

namespace App\\Entity;

use App\\Repository\\${entity}Repository;
use Doctrine\\ORM\\Mapping as ORM;

#[ORM\\Entity(repositoryClass: ${entity}Repository::class)]
class ${entity}
{
    #[ORM\\Id]
    #[ORM\\GeneratedValue]
    #[ORM\\Column]
    private ?int $id = null;

    #[ORM\\Column(length: 255)]
    private ?string $title = null;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getTitle(): ?string
    {
        return $this->title;
    }

    public function setTitle(string $title): static
    {
        $this->title = $title;
        return $this;
    }
}
`);
            fs.writeFileSync(repoFile, `<?php

namespace App\\Repository;

use App\\Entity\\${entity};
use Doctrine\\Bundle\\DoctrineBundle\\Repository\\ServiceEntityRepository;
use Doctrine\\Persistence\\ManagerRegistry;

/**
 * @extends ServiceEntityRepository<${entity}>
 */
class ${entity}Repository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, ${entity}::class);
    }
}
`);
            fs.writeFileSync(controllerFile, `<?php

namespace App\\Controller;

use App\\Repository\\${entity}Repository;
use Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController;
use Symfony\\Component\\HttpFoundation\\JsonResponse;
use Symfony\\Component\\Routing\\Attribute\\Route;

class ${entity}Controller extends AbstractController
{
    #[Route('/${route}', name: 'app_${route}_index', methods: ['GET'])]
    public function index(${entity}Repository $repository): JsonResponse
    {
        $items = array_map(
            static fn (${entity} $item) => ['id' => $item->getId(), 'title' => $item->getTitle()],
            $repository->findAll(),
        );

        return $this->json(['results' => $items]);
    }
}
`);
            return jsonResult({
                kind: 'symfony',
                entity,
                route: `/${route}`,
                files: [entityFile, repoFile, controllerFile],
                nextSteps: [
                    'Run doctrine migrations if Doctrine is configured (php bin/console make:migration / doctrine:migrations:migrate).',
                    'Ensure Doctrine ORM and attributes are enabled for the Entity mapping.',
                ],
            });
        }
        catch (error) {
            return errorResult(toErrorMessage(error));
        }
    });
}
//# sourceMappingURL=generateResources.js.map