<?php
/**
 * This file is part of the ForkBB <https://github.com/forkbb>.
 *
 * @copyright (c) Visman <mio.visman@yandex.ru, https://github.com/MioVisman>
 * @license   The MIT License (MIT)
 */

declare(strict_types=1);

namespace ForkBB\Models\Pages\Profile;

use ForkBB\Core\Image;
use ForkBB\Core\Validator;
use ForkBB\Core\Exceptions\MailException;
use ForkBB\Models\Page;
use ForkBB\Models\Pages\Profile;
use ForkBB\Models\User\User;
use function \ForkBB\__;

class Edit extends Profile
{
    /**
     * Паттерн для доступных к загрузке типов файлов
     * @var string
     */
    protected $accept = 'image/*';

    /**
     * Подготавливает данные для шаблона редактирования профиля
     */
    public function edit(array $args, string $method): Page
    {
        if (
            false === $this->initProfile($args['id'])
            || ! $this->rules->editProfile
        ) {
            return $this->c->Message->message('Bad request');
        }

        $this->c->Lang->load('validator');
        $this->c->Lang->load('profile_other');

        if ('POST' === $method) {
            if ($this->rules->rename) {
                $ruleUsername = 'required|string:trim|username';
            } else {
                $ruleUsername = 'absent';
            }

            if ($this->rules->setTitle) {
                $ruleTitle = 'string:trim|max:50|noURL';
            } else {
                $ruleTitle = 'absent';
            }

            if ($this->rules->useAvatar) {
                $ruleAvatar    = "image|max:{$this->c->Files->maxImgSize('K')}";
                $ruleDelAvatar = $this->curUser->avatar ? 'checkbox' : 'absent';
            } else {
                $ruleAvatar    = 'absent';
                $ruleDelAvatar = 'absent';
            }

            if ($this->user->isAdmMod) {
                $ruleAdminNote = 'string:trim|max:30';
            } else {
                $ruleAdminNote = 'absent';
            }

            if ($this->rules->editWebsite) {
                $ruleWebsite = 'string:trim|max:100'; // ???? валидация url?
            } else {
                $ruleWebsite = 'absent';
            }

            if ($this->rules->useSignature) {
                $ruleSignature = "string:trim|max:{$this->curUser->g_sig_length}|check_signature";
            } else {
                $ruleSignature = 'absent';
            }

            $v = $this->c->Validator->reset()
                ->addValidators([
                    'check_signature' => [$this, 'vCheckSignature'],
                ])->addRules([
                    'token'         => 'token:EditUserProfile',
                    'username'      => $ruleUsername,
                    'title'         => $ruleTitle,
                    'upload_avatar' => $ruleAvatar,
                    'delete_avatar' => $ruleDelAvatar,
                    'admin_note'    => $ruleAdminNote,
                    'realname'      => 'string:trim|max:40|noURL:1',
                    'gender'        => 'required|integer|in:0,1,2',
                    'location'      => 'string:trim|max:30|noURL:1',
                    'email_setting' => 'required|integer|in:0,1,2',
                    'url'           => $ruleWebsite,
                    'signature'     => $ruleSignature,
                    'save'          => 'required|string',
                ])->addAliases([
                    'username'      => 'Username',
                    'title'         => 'Title',
                    'upload_avatar' => 'New avatar',
                    'delete_avatar' => 'Delete avatar',
                    'admin_note'    => 'Admin note',
                    'realname'      => 'Realname',
                    'gender'        => 'Gender',
                    'location'      => 'Location',
                    'email_setting' => 'Email settings label',
                    'url'           => 'Website',
                    'signature'     => 'Signature',
                ])->addArguments([
                    'token'             => $args,
                    'username.username' => $this->curUser,
                ])->addMessages([
                ]);

            $valid = $v->validation($_FILES + $_POST);
            $data  = $v->getData();
            unset($data['token'], $data['upload_avatar'], $data['delete_avatar']);

            if ($valid) {
                if (
                    $v->delete_avatar
                    || $v->upload_avatar instanceof Image
                ) {
                    $this->curUser->deleteAvatar();
                }

                if ($v->upload_avatar instanceof Image) {
                    $name   = $this->c->Secury->randomPass(8);
                    $path   = $this->c->DIR_PUBLIC . "{$this->c->config->o_avatars_dir}/{$name}.(jpg|png|gif|webp)";
                    $result = $v->upload_avatar
                        ->rename(true)
                        ->rewrite(false)
                        ->resize($this->c->config->i_avatars_width, $this->c->config->i_avatars_height)
                        ->toFile($path, $this->c->config->i_avatars_size);

                    if (true === $result) {
                        $this->curUser->avatar = $v->upload_avatar->name() . '.' . $v->upload_avatar->ext();
                    }
                }

                $this->curUser->replAttrs($data, true);

                $this->c->users->update($this->curUser);

                return $this->c->Redirect->page('EditUserProfile', $args)->message('Profile redirect');
            } else {
                $this->fIswev = $v->getErrors();

                $this->curUser->replAttrs($data);
            }
        }

        $this->crumbs     = $this->crumbs(
            [
                $this->c->Router->link('EditUserProfile', $args),
                __('Editing profile'),
            ]
        );
        $this->form       = $this->form($args);
        $this->actionBtns = $this->btns('edit');

        return $this;
    }

    /**
     * Дополнительная проверка signature
     */
    public function vCheckSignature(Validator $v, $signature)
    {
        if ('' != $signature) {
            $prepare = null;

            // после цензуры текст сообщения пустой
            if ('' == $this->c->censorship->censor($signature)) {
                $v->addError('No signature after censoring');
            // количество строк
            } elseif (\substr_count($signature, "\n") >= $this->curUser->g_sig_lines) {
                $v->addError('Signature has too many lines');
            // проверка парсером
            } else {
                $prepare   = true;
                $signature = $this->c->Parser->prepare($signature, true); //????

                foreach ($this->c->Parser->getErrors([], [], true) as $error) {
                    $prepare = false;
                    $v->addError($error);
                }
            }

            // текст сообщения только заглавными буквами
            if (
                true === $prepare
                && ! $this->user->isAdmin
                && '0' == $this->c->config->p_sig_all_caps
            ) {
                $text = $this->c->Parser->getText();

                if (
                    \preg_match('%\p{Lu}%u', $text)
                    && ! \preg_match('%\p{Ll}%u', $text)
                ) {
                    $v->addError('All caps signature');
                }
            }
        }

        return $signature;
    }

    /**
     * Создает массив данных для формы
     */
    protected function form(array $args): array
    {
        $form = [
            'action' => $this->c->Router->link('EditUserProfile', $args),
            'hidden' => [
                'token' => $this->c->Csrf->create('EditUserProfile', $args),
            ],
            'sets'   => [],
            'btns'   => [
                'save' => [
                    'type'  => 'submit',
                    'value' => __('Save changes'),
                ],
            ],
        ];

        // имя, титул и аватара
        $fields = [];
        if ($this->rules->rename) {
            $fields['username'] = [
                'type'      => 'text',
                'maxlength' => '25',
                'caption'   => 'Username',
                'required'  => true,
                'pattern'   => '^.{2,25}$',
                'value'     => $this->curUser->username,
            ];
        } else {
            $fields['username'] = [
                'class'   => ['pline'],
                'type'    => 'str',
                'caption' => 'Username',
                'value'   => $this->curUser->username,
            ];
        }
        if ($this->rules->changeGroup) {
            $fields['group'] = [
                'type'    => 'link',
                'caption' => 'Group',
                'value'   => $this->curUser->group_id ? $this->curUser->g_title : __('Change user group'),
                'title'   => __('Change user group'),
                'href'    => $this->linkChangeGroup(),
            ];
        } else {
            $fields['group'] = [
                'class'   => ['pline'],
                'type'    => 'str',
                'caption' => 'Group',
                'value'   => $this->curUser->group_id ? $this->curUser->g_title : '-',
            ];
        }
        if ($this->rules->confModer) {
            $fields['configure-moderator'] = [
                'type'    => 'link',
                'value'   => __('Configure moderator rights'),
                'title'   => __('Configure moderator rights'),
                'href'    => $this->c->Router->link('EditUserModeration', $args),
            ];
        }
        if ($this->rules->setTitle) {
            $fields['title'] = [
                'type'      => 'text',
                'maxlength' => '50',
                'caption'   => 'Title',
                'value'     => $this->curUser->title,
                'help'      => 'Leave blank',
            ];
        } else {
            $fields['title'] = [
                'class'   => ['pline'],
                'type'    => 'str',
                'caption' => 'Title',
                'value'   => $this->curUser->title(),
            ];
        }
        if ($this->rules->editPass) {
            $fields['change_pass'] = [
                'type'  => 'link',
                'value' => __('Change passphrase'),
                'href'  => $this->c->Router->link('EditUserPass', $args),
            ];
        }
        if ($this->rules->useAvatar) {
            if (! $this->curUser->avatar) {
                $fields['avatar'] = [
                    'class'   => ['pline'],
                    'type'    => 'str',
                    'caption' => 'Avatar',
                    'value'   => __('Not uploaded'),
                ];
            } elseif ($this->curUser->avatar) {
                $fields['avatar'] = [
                    'type'    => 'yield',
                    'caption' => 'Avatar',
                    'value'   => 'avatar',
                ];
            }

            $form['enctype'] = 'multipart/form-data';
            $form['hidden']['MAX_FILE_SIZE'] = $this->c->Files->maxImgSize();

            if ($this->curUser->avatar) {
                $fields['delete_avatar'] = [
                    'type'    => 'checkbox',
                    'label'   => 'Delete avatar',
                    'checked' => false,
                ];
            }

            $fields['upload_avatar'] = [
                'type'    => 'file',
                'caption' => 'New avatar',
                'help'    => ['New avatar info',
                    \ForkBB\num($this->c->config->i_avatars_width),
                    \ForkBB\num($this->c->config->i_avatars_height),
                    \ForkBB\num($this->c->config->i_avatars_size),
                    \ForkBB\size($this->c->config->i_avatars_size)
                ],
                'accept' => $this->accept,
            ];
        }
        $form['sets']['header'] = [
            'class'  => ['header-edit'],
#            'legend' => 'Options',
            'fields' => $fields,
        ];

        // примечание администрации
        if ($this->user->isAdmMod) {
            $form['sets']['note'] = [
                'class'  => ['data-edit'],
                'legend' => 'Admin note',
                'fields' => [
                    'admin_note' => [
                        'type'      => 'text',
                        'maxlength' => '30',
                        'caption'   => 'Admin note',
                        'value'     => $this->curUser->admin_note,
                    ],
                ],
            ];
        }

        // личное
        $fields = [];
        $fields['realname'] = [
            'type'      => 'text',
            'maxlength' => '40',
            'caption'   => 'Realname',
            'value'     => $this->curUser->realname,
        ];
        $genders = [
            0 => __('Do not display'),
            1 => __('Male'),
            2 => __('Female'),
        ];
        $fields['gender'] = [
            'class'   => ['block'],
            'type'    => 'radio',
            'value'   => $this->curUser->gender,
            'values'  => $genders,
            'caption' => 'Gender',
        ];
        $fields['location'] = [
            'type'      => 'text',
            'maxlength' => 30,
            'caption'   => 'Location',
            'value'     => $this->curUser->location,
        ];
        $form['sets']['personal'] = [
            'class'  => ['data-edit'],
            'legend' => 'Personal information',
            'fields' => $fields,
        ];

        // контактная информация
        $fields = [];
        if ($this->rules->viewOEmail) {
            $fields['open-email'] = [
                'class'   => ['pline'],
                'type'    => 'str',
                'caption' => 'Email info',
                'value'   => $this->curUser->censorEmail,
            ];
        }
        if ($this->rules->editEmail) {
            $fields['change_email'] = [
                'type'  => 'link',
                'value' => __($this->rules->confirmEmail ? 'To confirm/change email' : 'To change email'),
                'href'  => $this->c->Router->link('EditUserEmail', $args),
            ];
        }
        $fields['email_setting'] = [
            'class'   => ['block'],
            'type'    => 'radio',
            'value'   => $this->curUser->email_setting,
            'values'  => [
                0 => __('Display e-mail label'),
                1 => __('Hide allow form label'),
                2 => __('Hide both label'),
            ],
            'caption' => 'Email settings label',
        ];

        if ($this->rules->editWebsite) {
            $fields['url'] = [
                'id'        => 'website',
                'type'      => 'text',
                'maxlength' => '100',
                'caption'   => 'Website',
                'value'     => $this->curUser->url,
            ];
        } elseif (
            $this->rules->viewWebsite
            && $this->curUser->url
        ) {
            $fields['url'] = [
                'id'      => 'website',
                'class'   => ['pline'],
                'type'    => 'link',
                'caption' => 'Website',
                'value'   => $this->curUser->censorUrl,
                'href'    => $this->curUser->censorUrl,
            ];
        }
        $form['sets']['contacts'] = [
            'class'  => ['data-edit'],
            'legend' => 'Contact details',
            'fields' => $fields,
        ];

        // подпись
        if ($this->rules->useSignature) {
            $fields = [];
            $fields['signature'] = [
                'type'    => 'textarea',
                'value'   => $this->curUser->signature,
                'caption' => 'Signature',
                'help'    => ['Sig max size', \ForkBB\num($this->curUser->g_sig_length), \ForkBB\num($this->curUser->g_sig_lines)],
            ];
            $form['sets']['signature'] = [
                'class'  => ['data-edit'],
                'legend' => 'Signature',
                'fields' => $fields,
            ];
        }

        return $form;
    }
}
