<?php
declare(strict_types=1);

namespace Celena\Plugin\Leads\Admin;

use Celena\Core\Database\Connection;
use Celena\Core\Http\Pagination;
use Celena\Core\Http\Request;
use Celena\Core\Http\Response;
use Celena\Core\Security\Auth;
use Celena\Core\Security\Csrf;
use Celena\Core\Security\Filter;
use Celena\Core\Template\Engine;
use Celena\Module\AdminBase\AdminController;
use Celena\Module\Settings\Options;
use Celena\Plugin\Leads\Repositories\FormRepository;

/**
 * Конструктор форм: список, создание/редактирование (поля любых типов), заявки, CSV.
 * Маршруты вне группы AuthMiddleware — авторизацию проверяем явно.
 */
final class FormsAdminController extends AdminController
{
    private const TYPES = ['text', 'textarea', 'email', 'tel', 'number', 'date', 'select', 'radio', 'checkboxes', 'checkbox', 'consent', 'hidden'];

    private FormRepository $repo;

    public function __construct(Engine $engine, Auth $auth, Options $options, private readonly Connection $conn)
    {
        parent::__construct($engine, $auth, $options);
        $this->repo = new FormRepository($conn);
    }

    public function index(Request $request): Response
    {
        if ($this->auth->user() === null) return Response::redirect('/admin/login');
        $forms = $this->repo->all();
        foreach ($forms as &$f) {
            $f['is_default'] = !empty($f['settings']['is_default']) ? '1' : '';
            $f['fields_count'] = is_array($f['fields'] ?? null) ? count($f['fields']) : 0;
            $f['subs'] = $this->repo->submissionsCount((int) $f['id']);
        }
        unset($f);
        return $this->view('plugins/leads/admin/forms_index', [
            'forms'    => $forms,
            'is_empty' => $forms === [] ? '1' : '',
        ], 'forms', 'Формы');
    }

    public function create(Request $request): Response
    {
        if ($this->auth->user() === null) return Response::redirect('/admin/login');
        return $this->form([
            'id' => 0, 'slug' => '', 'title' => '', 'fields' => [], 'settings' => [],
        ], 'Новая форма', '/admin/forms/create');
    }

    public function edit(Request $request, array $params): Response
    {
        if ($this->auth->user() === null) return Response::redirect('/admin/login');
        $form = $this->repo->find(Filter::int($params['id'] ?? 0));
        if ($form === null) return $this->redirect('/admin/forms', 'Форма не найдена.', 'error');
        return $this->form($form, 'Форма: ' . (string) $form['title'], '/admin/forms/' . (int) $form['id'] . '/update');
    }

    public function store(Request $request): Response
    {
        if ($this->auth->user() === null) return Response::redirect('/admin/login');
        if (!Csrf::validate((string) $request->input('_csrf'))) return $this->redirect('/admin/forms', 'CSRF.', 'error');

        $title = Filter::string($request->input('title'), 191);
        if ($title === '') return $this->redirect('/admin/forms/create', 'Укажите название формы.', 'error');
        $slug = $this->repo->uniqueSlug(Filter::slug($request->input('slug') ?: $title));
        $fields = $this->extractFields($request, []);
        $settings = $this->extractSettings($request, []);
        $this->repo->create($slug, $title, $fields, $settings);
        return $this->redirect('/admin/forms', 'Форма создана.');
    }

    public function update(Request $request, array $params): Response
    {
        if ($this->auth->user() === null) return Response::redirect('/admin/login');
        if (!Csrf::validate((string) $request->input('_csrf'))) return $this->redirect('/admin/forms', 'CSRF.', 'error');
        $id = Filter::int($params['id'] ?? 0);
        $form = $this->repo->find($id);
        if ($form === null) return $this->redirect('/admin/forms', 'Форма не найдена.', 'error');

        $title = Filter::string($request->input('title'), 191) ?: (string) $form['title'];
        $fields = $this->extractFields($request, is_array($form['fields'] ?? null) ? $form['fields'] : []);
        $settings = $this->extractSettings($request, is_array($form['settings'] ?? null) ? $form['settings'] : []);
        $this->repo->update($id, $title, $fields, $settings);
        return $this->redirect('/admin/forms/' . $id . '/edit', 'Сохранено.');
    }

    public function delete(Request $request, array $params): Response
    {
        if ($this->auth->user() === null) return Response::redirect('/admin/login');
        if (!Csrf::validate((string) $request->input('_csrf'))) return $this->redirect('/admin/forms', 'CSRF.', 'error');
        $form = $this->repo->find(Filter::int($params['id'] ?? 0));
        if ($form === null) return $this->redirect('/admin/forms', 'Форма не найдена.', 'error');
        if (!empty($form['settings']['is_default'])) {
            return $this->redirect('/admin/forms', 'Нельзя удалить основную форму лендинга.', 'error');
        }
        $this->repo->delete((int) $form['id']);
        return $this->redirect('/admin/forms', 'Форма удалена.');
    }

    // ── Заявки ──

    public function submissions(Request $request, array $params): Response
    {
        if ($this->auth->user() === null) return Response::redirect('/admin/login');
        $form = $this->repo->find(Filter::int($params['id'] ?? 0));
        if ($form === null) return $this->redirect('/admin/forms', 'Форма не найдена.', 'error');

        $filter = Filter::in($request->query('status'), ['new', 'done'], '');
        $page = Filter::int($request->query('page', 1), 1);
        $total = $this->repo->submissionsCount((int) $form['id'], $filter);
        $p = new Pagination($page, 30, $total);
        $subs = $this->repo->submissions((int) $form['id'], $filter, $p->perPage, $p->offset);

        // Динамические колонки из схемы + строки.
        $cols = [];
        foreach ((array) ($form['fields'] ?? []) as $f) {
            if (is_array($f) && ($f['type'] ?? '') !== 'hidden') {
                $cols[] = ['key' => (string) ($f['key'] ?? ''), 'label' => (string) ($f['label'] ?? $f['key'] ?? '')];
            }
        }
        $rows = [];
        foreach ($subs as $s) {
            $cells = [];
            foreach ($cols as $c) {
                $v = $s['data'][$c['key']] ?? '';
                $cells[] = ['v' => is_array($v) ? implode(', ', $v) : (string) $v];
            }
            $rows[] = [
                'id' => (int) $s['id'], 'created_at' => (string) $s['created_at'],
                'status' => (string) $s['status'], 'cells' => $cells,
            ];
        }

        return $this->view('plugins/leads/admin/forms_submissions', [
            'form_id'   => (int) $form['id'],
            'form_title'=> (string) $form['title'],
            'cols'      => $cols,
            'rows'      => $rows,
            'is_empty'  => $rows === [] ? '1' : '',
            'current_filter' => $filter,
            'new_count' => $this->repo->submissionsCount((int) $form['id'], 'new'),
            'pagination'=> $p->toArray('/admin/forms/' . (int) $form['id'] . '/submissions?page=:page' . ($filter !== '' ? '&status=' . $filter : '')),
        ], 'forms', 'Заявки: ' . (string) $form['title']);
    }

    public function subStatus(Request $request, array $params): Response
    {
        if ($this->auth->user() === null) return Response::redirect('/admin/login');
        if (!Csrf::validate((string) $request->input('_csrf'))) return $this->redirect('/admin/forms', 'CSRF.', 'error');
        $id = Filter::int($params['id'] ?? 0);
        $status = Filter::in($request->input('status'), ['new', 'done'], 'new');
        $this->repo->setSubmissionStatus($id, $status);
        return $this->redirect($request->header('referer') ?: '/admin/forms', 'Статус обновлён.');
    }

    public function subDelete(Request $request, array $params): Response
    {
        if ($this->auth->user() === null) return Response::redirect('/admin/login');
        if (!Csrf::validate((string) $request->input('_csrf'))) return $this->redirect('/admin/forms', 'CSRF.', 'error');
        $this->repo->deleteSubmission(Filter::int($params['id'] ?? 0));
        return $this->redirect($request->header('referer') ?: '/admin/forms', 'Заявка удалена.');
    }

    public function export(Request $request, array $params): Response
    {
        if ($this->auth->user() === null) return Response::redirect('/admin/login');
        $form = $this->repo->find(Filter::int($params['id'] ?? 0));
        if ($form === null) return $this->redirect('/admin/forms', 'Форма не найдена.', 'error');

        $cols = [];
        foreach ((array) ($form['fields'] ?? []) as $f) {
            if (is_array($f) && ($f['type'] ?? '') !== 'hidden') {
                $cols[] = ['key' => (string) ($f['key'] ?? ''), 'label' => (string) ($f['label'] ?? $f['key'] ?? '')];
            }
        }
        $subs = $this->repo->submissions((int) $form['id'], '', 100000, 0);

        $fh = fopen('php://temp', 'r+');
        fwrite($fh, "\xEF\xBB\xBF");
        $head = ['Дата', 'Статус'];
        foreach ($cols as $c) $head[] = $c['label'] !== '' ? $c['label'] : $c['key'];
        fputcsv($fh, $head, ',', '"', '');
        foreach ($subs as $s) {
            $line = [(string) $s['created_at'], (string) $s['status']];
            foreach ($cols as $c) {
                $v = $s['data'][$c['key']] ?? '';
                $line[] = is_array($v) ? implode(', ', $v) : (string) $v;
            }
            fputcsv($fh, $line, ',', '"', '');
        }
        rewind($fh);
        $csv = stream_get_contents($fh) ?: '';
        fclose($fh);
        return new Response($csv, 200, [
            'Content-Type'        => 'text/csv; charset=UTF-8',
            'Content-Disposition' => 'attachment; filename="form-' . (string) $form['slug'] . '-' . date('Ymd') . '.csv"',
        ]);
    }

    // ── helpers ──

    private function form(array $form, string $title, string $action): Response
    {
        $s = is_array($form['settings'] ?? null) ? $form['settings'] : [];
        $emails = $s['notify_emails'] ?? [];
        return $this->view('plugins/leads/admin/forms_form', [
            'page_title'  => $title,
            'action'      => $action,
            'is_edit'     => (int) ($form['id'] ?? 0) > 0 ? '1' : '',
            'is_default'  => !empty($s['is_default']) ? '1' : '',
            'f_id'        => (int) ($form['id'] ?? 0),
            'f_title'     => (string) ($form['title'] ?? ''),
            'f_slug'      => (string) ($form['slug'] ?? ''),
            'fields_json' => json_encode(array_values((array) ($form['fields'] ?? [])), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            's_submit'    => (string) ($s['submit_text'] ?? ''),
            's_ok_title'  => (string) ($s['ok_title'] ?? ''),
            's_ok_text'   => (string) ($s['ok_text'] ?? ''),
            's_emails'    => is_array($emails) ? implode(', ', $emails) : (string) $emails,
            's_tg'        => !empty($s['telegram_enabled']) ? '1' : '',
            's_value'     => (string) ($s['lead_value'] ?? '0'),
            's_conv'      => (string) ($s['conversion_send_to'] ?? ''),
        ], 'forms', $title);
    }

    /** @return array<int, array<string,mixed>> */
    private function extractFields(Request $request, array $existing): array
    {
        $raw = json_decode((string) $request->input('fields_json', '[]'), true);
        if (!is_array($raw)) return [];
        $out = [];
        $usedKeys = [];
        foreach ($raw as $f) {
            if (!is_array($f)) continue;
            $type = in_array(($f['type'] ?? ''), self::TYPES, true) ? (string) $f['type'] : 'text';
            $label = Filter::string($f['label'] ?? '', 191);
            $key = Filter::slug($f['key'] ?? '', 60);
            $key = $key !== '' ? str_replace('-', '_', $key) : 'field';
            $base = $key; $i = 2;
            while (in_array($key, $usedKeys, true)) { $key = $base . '_' . $i; $i++; }
            $usedKeys[] = $key;

            $field = [
                'key'      => $key,
                'label'    => $label,
                'type'     => $type,
                'required' => !empty($f['required']),
                'width'    => (($f['width'] ?? 'full') === 'half') ? 'half' : 'full',
            ];
            $ph = Filter::string($f['placeholder'] ?? '', 191);
            if ($ph !== '') $field['placeholder'] = $ph;
            $help = Filter::string($f['help'] ?? '', 191);
            if ($help !== '') $field['help'] = $help;
            if (in_array($type, ['select', 'radio', 'checkboxes'], true)) {
                $field['options'] = $this->cleanOptions($f['options'] ?? []);
            }
            // Сохраняем lang_key, если поле не менялось (JS сбрасывает при правке подписи).
            if (!empty($f['lang_key'])) {
                $field['lang_key'] = Filter::string($f['lang_key'], 120);
            }
            $out[] = $field;
        }
        return $out;
    }

    /** @return array<int, mixed> */
    private function cleanOptions(mixed $options): array
    {
        $out = [];
        if (is_array($options)) {
            foreach ($options as $o) {
                if (is_array($o)) {
                    // объект с lang (мультиязычная опция) — сохраняем как есть
                    $val = (string) ($o['value'] ?? '');
                    if ($val !== '') $out[] = array_filter(['value' => $val, 'lang' => $o['lang'] ?? null, 'label' => $o['label'] ?? null], fn ($x) => $x !== null && $x !== '');
                } else {
                    $v = Filter::string($o, 120);
                    if ($v !== '') $out[] = $v;
                }
            }
        }
        return $out;
    }

    /** @return array<string,mixed> */
    private function extractSettings(Request $request, array $existing): array
    {
        $emails = [];
        foreach (preg_split('/[,;\n]+/', (string) $request->input('notify_emails', '')) as $e) {
            $e = trim($e);
            if ($e !== '' && filter_var($e, FILTER_VALIDATE_EMAIL)) $emails[] = $e;
        }
        $val = (float) str_replace(',', '.', (string) $request->input('lead_value', '0'));
        $merged = array_merge($existing, [
            'submit_text'        => Filter::string($request->input('submit_text'), 120),
            'ok_title'           => Filter::string($request->input('ok_title'), 200),
            'ok_text'            => Filter::string($request->input('ok_text'), 500),
            'notify_emails'      => $emails,
            'telegram_enabled'   => Filter::bool($request->input('telegram_enabled')),
            'lead_value'         => $val >= 0 ? $val : 0,
            'lead_currency'      => 'EUR',
            'conversion_send_to' => Filter::string($request->input('conversion_send_to'), 120),
        ]);
        return $merged;
    }
}
