<?php

declare(strict_types=1);

namespace PortalPeople\datadash\controllers;

use PortalPeople\datadash\models\ConfigForm;
use Yii;
use yii\filters\AccessControl;
use yii\filters\VerbFilter;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\web\Response;
use yii\widgets\ActiveForm;

/**
 * ConfigController
 *
 * CRUD UI for named DataDash external database connections.
 * Accessible at /datadash/config/index.
 */
class ConfigController extends Controller
{
    public function behaviors(): array
    {
        return [
            'access' => [
                'class' => AccessControl::class,
                'rules' => [
                    [
                        'allow' => true,
                        'roles' => ['@'],
                    ],
                ],
            ],
            'verbs' => [
                'class' => VerbFilter::class,
                'actions' => [
                    'validate'       => ['POST'],
                    'test-connection'=> ['POST'],
                    'list-tables'    => ['POST'],
                    'delete'         => ['POST'],
                    'do-generate'    => ['POST'],
                ],
            ],
        ];
    }

    // ─── Index — list connections ──────────────────────────────────────────────

    public function actionIndex(): string
    {
        $connections = ConfigForm::loadAllConnections();

        return $this->render('index', ['connections' => $connections]);
    }

    // ─── Create ───────────────────────────────────────────────────────────────

    /**
     * @return string|Response
     */
    public function actionCreate()
    {
        $model = new ConfigForm();

        if ($model->load(Yii::$app->request->post()) && $model->validate()) {
            if ($model->saveToParams()) {
                Yii::$app->session->setFlash('success', "Connection '{$model->name}' saved.");
                return $this->redirect(['/ngauge-datadash/config/index']);
            }
            Yii::$app->session->setFlash('error', 'Failed to write configuration — check params-local.php permissions.');
        }

        return $this->render('create', ['model' => $model]);
    }

    // ─── Update ───────────────────────────────────────────────────────────────

    /**
     * @return string|Response
     */
    public function actionUpdate(string $name)
    {
        $model = new ConfigForm();

        if (!$model->loadFromParams($name)) {
            throw new NotFoundHttpException("Connection '{$name}' not found.");
        }

        if ($model->load(Yii::$app->request->post()) && $model->validate()) {
            // Preserve the original name — name is not editable after creation
            $model->name = $name;

            if ($model->saveToParams()) {
                Yii::$app->session->setFlash('success', "Connection '{$name}' updated.");
                return $this->redirect(['/ngauge-datadash/config/index']);
            }
            Yii::$app->session->setFlash('error', 'Failed to write configuration — check params-local.php permissions.');
        }

        return $this->render('update', ['model' => $model]);
    }

    // ─── Delete ───────────────────────────────────────────────────────────────

    /**
     * @return Response
     */
    public function actionDelete(): Response
    {
        $name = (string) Yii::$app->request->post('name', '');

        if ($name !== '' && ConfigForm::deleteFromParams($name)) {
            Yii::$app->session->setFlash('success', "Connection '{$name}' deleted.");
        } else {
            Yii::$app->session->setFlash('error', 'Could not delete connection.');
        }

        return $this->redirect(['/ngauge-datadash/config/index']);
    }

    // ─── AJAX validation ───────────────────────────────────────────────────────

    /**
     * @return array<string, list<string>>
     */
    public function actionValidate(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

        $model = new ConfigForm();
        if ($model->load(Yii::$app->request->post())) {
            return ActiveForm::validate($model);
        }

        return [];
    }

    // ─── Test connection ───────────────────────────────────────────────────────

    /**
     * @return array{success: bool, message: string, details?: array<string, mixed>}
     */
    public function actionTestConnection(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

        $model = new ConfigForm();
        if ($model->load(Yii::$app->request->post()) && $model->validate()) {
            return $model->testConnection();
        }

        return [
            'success' => false,
            'message' => 'Invalid form data — please correct the errors and try again.',
            'errors'  => $model->errors,
        ];
    }

    // ─── List tables ───────────────────────────────────────────────────────────

    /**
     * @return array{success: bool, message: string, tables?: list<array<string, mixed>>}
     */
    public function actionListTables(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

        $model = new ConfigForm();
        $post  = Yii::$app->request->post();

        if (!empty($post)) {
            $model->load($post);
        } else {
            // Fall back to the named connection from query string
            $name = (string) Yii::$app->request->get('name', '');
            $model->loadFromParams($name);
        }

        if (!$model->validate()) {
            return [
                'success' => false,
                'message' => 'Invalid configuration — please correct the errors and try again.',
                'errors'  => $model->errors,
            ];
        }

        return $model->listTables();
    }

    // ─── Gii generate models ───────────────────────────────────────────────────

    /**
     * Show the model generation form for a specific connection.
     * Tables are loaded server-side so the user can check/uncheck them.
     *
     * @return string|Response
     */
    public function actionGenerate(string $name)
    {
        $model = new ConfigForm();

        if (!$model->loadFromParams($name)) {
            throw new NotFoundHttpException("Connection '{$name}' not found.");
        }

        // Pre-fetch table list for the checkbox grid
        $tablesResult = $model->listTables();
        $tables = $tablesResult['success'] ? ($tablesResult['tables'] ?? []) : [];
        $tablesError = $tablesResult['success'] ? null : $tablesResult['message'];

        return $this->render('generate', [
            'model'       => $model,
            'tables'      => $tables,
            'tablesError' => $tablesError,
        ]);
    }

    /**
     * Run Gii model generation from the posted selection.
     *
     * @return string|Response
     */
    public function actionDoGenerate()
    {
        $request   = Yii::$app->request;
        $name      = (string) $request->post('name', '');
        $namespace = (string) $request->post('namespace', 'common\models\remote');
        $selected  = (array) $request->post('tables', []);

        $model = new ConfigForm();

        if ($name === '' || !$model->loadFromParams($name)) {
            throw new NotFoundHttpException("Connection '{$name}' not found.");
        }

        if (empty($selected)) {
            Yii::$app->session->setFlash('error', 'No tables selected.');
            return $this->redirect(['/ngauge-datadash/config/generate', 'name' => $name]);
        }

        $result = $model->generateModels($selected, $namespace);

        if ($result['success']) {
            $fileList = implode("\n", $result['files'] ?? []);
            Yii::$app->session->setFlash('success', $result['message'] . ($fileList ? "\n" . $fileList : ''));
        } else {
            Yii::$app->session->setFlash('error', $result['message']);
        }

        return $this->redirect(['/ngauge-datadash/config/generate', 'name' => $name]);
    }
}
