<?php


namespace App\Http\Controllers;

use App\Models\Table;
use App\Models\User;
use App\Tables\Changeset;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Input;
use MightyPork\Exceptions\SimpleValidationException;
use MightyPork\Utils\Utils;

class TableEditController extends Controller
{
    /**
     * Initialize the session-stored changeset, if not set yet
     *
     * @param Table $table
     * @return Changeset
     */
    private function getChangeset(Table $table)
    {
        if (Input::has('reset')) {
            session()->forget($table->draftSessionKey);
        }

        /** @var Changeset $changeset */
        return session()->remember($table->draftSessionKey, function () use ($table) {
            $changeset = new Changeset();
            $changeset->table = $table;
            $changeset->revision = $table->revision;
            return $changeset;
        });
    }

    private function storeChangeset(Changeset $chs)
    {
        session()->put($chs->table->draftSessionKey, $chs);
    }

    /**
     * Discard draft and redirect to table view
     */
    public function discard(User $user, string $table)
    {
        /** @var Table $tableModel */
        $tableModel = $user->tables()->where('name', $table)->first();
        if ($tableModel === null) abort(404, "No such table.");

        session()->forget($tableModel->draftSessionKey);

        return redirect($tableModel->viewRoute);
    }

    public function draft(User $user, string $table, $tab = null)
    {
        /** @var Table $tableModel */
        $tableModel = $user->tables()->where('name', $table)->first();
        if ($tableModel === null) abort(404, "No such table.");

        if ($tab == null) $tab = 'edit-rows';
        $tabs = ['edit-rows', 'add-rows', 'manage-columns', 'review'];
        if (!in_array($tab, $tabs)) abort(404, "No such tab: $tab");

        $changeset = $this->getChangeset($tableModel);

        if (Input::has('dump')) {
            dd($changeset);
        }

        return $this->{camel_case($tab)}($changeset);
    }

    /** @noinspection PhpUnusedPrivateMethodInspection */
    private function editRows(Changeset $changeset)
    {
        $revision = $changeset->revision;
        $columns = $changeset->fetchAndTransformColumns();
        $rows = $revision->rowsData($columns, true, false)->paginate(25, []);

        return view('table.propose.edit-rows', [
            'changeset' => $changeset,
            'table' => $changeset->table,
            'columns' => collect($columns),
            'rows' => $rows,
        ]);
    }

    /** @noinspection PhpUnusedPrivateMethodInspection */
    private function addRows(Changeset $changeset)
    {
        $columns = $changeset->fetchAndTransformColumns();
        $rows = $changeset->getAddedRows(25);

        return view('table.propose.add-rows', [
            'changeset' => $changeset,
            'table' => $changeset->table,
            'columns' => collect($columns),
            'rows' => $rows,
        ]);
    }

    public function draftUpdate(Request $request, User $user, string $table)
    {
        /** @var Table $tableModel */
        $tableModel = $user->tables()->where('name', $table)->first();
        if ($tableModel === null) abort(404, "No such table.");

        $changeset = $this->getChangeset($tableModel);

        $input = objBag($request->all(), false);

        try {
            $code = 200;
            switch ($input->action) {
                case 'row.update':
                    $data = (object)$input->data;
                    $changeset->rowUpdate($data);

                    $resp = $changeset->fetchAndTransformRow($data->_id);
                    break;

                case 'row.remove':
                    $isNew = $changeset->isNewRow($input->id);
                    $changeset->rowRemove($input->id);
                    $resp = $isNew ? null : $changeset->fetchAndTransformRow($input->id);
                    break;

                case 'row.restore':
                    $changeset->rowRestore($input->id);
                    $resp = $changeset->fetchAndTransformRow($input->id);
                    break;

                case 'rows.add':
                    $changeset->addBlankRows($input->count);

                    // rows.add is sent via a form
                    if ($input->has('redirect')) {
                        return redirect($input->redirect);
                    } else {
                        $resp = null;
                    }
                    break;

                case 'rows.add-csv':
                    try {
                        $changeset->addFilledRows(Utils::csvToArray($input->data));
                    } catch (\Exception $e) {
                        return $this->backWithErrors(['data' => $e->getMessage()]);
                    }

                    // rows.add-csv is sent via a form
                    if ($input->has('redirect')) {
                        return redirect($input->redirect);
                    } else {
                        $resp = null;
                    }
                    break;

                default:
                    $resp = "Bad Action";
                    $code = 400;
                    break;
            }
        } catch (SimpleValidationException $e) {
            return $this->jsonResponse(['errors' => $e->getMessageBag()->getMessages()], 400);
        }

        $this->storeChangeset($changeset);

        return $this->jsonResponse($resp, $code);
    }
}