<?php

namespace App\Controllers;

use App\Models\OrganizationMembershipModel;
use App\Models\OrganizationModel;
use App\Models\UserModel;

class Auth extends BaseController
{
    private UserModel $users;
    private OrganizationModel $organizations;
    private OrganizationMembershipModel $memberships;

    public function __construct()
    {
        $this->users = new UserModel();
        $this->organizations = new OrganizationModel();
        $this->memberships = new OrganizationMembershipModel();
    }

    public function login()
    {
        if (session()->get('auth_user')) {
            return redirect()->to(site_url('dashboard'));
        }

        return view('auth/login');
    }

    public function register()
    {
        if (session()->get('auth_user')) {
            return redirect()->to(site_url('dashboard'));
        }

        return view('auth/register');
    }

    public function account()
    {
        $user = $this->users->find((int) $this->authUser()['id']);
        if (! $user) {
            return redirect()->to(site_url('logout'))->with('error', 'Sessao invalida. Inicia sessão novamente.');
        }

        return view('auth/account', [
            'title' => 'Minha conta',
            'active' => 'account',
            'user' => $user,
        ]);
    }

    public function authenticate()
    {
        $credentials = [
            'email' => trim((string) $this->request->getPost('email')),
            'password' => (string) $this->request->getPost('password'),
        ];

        $rules = [
            'email' => 'required|valid_email',
            'password' => 'required|min_length[6]',
        ];

        if (! $this->validateData($credentials, $rules)) {
            return redirect()->back()
                ->withInput()
                ->with('errors', $this->validator->getErrors())
                ->with('error', 'Credenciais invalidas.');
        }

        $user = $this->users->findActiveByEmail($credentials['email']);

        if (! $user || ! password_verify($credentials['password'], $user['password_hash'])) {
            return redirect()->back()->withInput()->with('error', 'Email ou palavra-passe invalidos.');
        }

        session()->regenerate();
        session()->set('auth_user', [
            'id' => $user['id'],
            'name' => $user['name'],
            'email' => $user['email'],
            'role' => $user['role'],
        ]);

        $membership = $this->memberships->activeForUser((int) $user['id'])[0] ?? null;
        if ($membership) {
            session()->set('current_organization_id', (int) $membership['organization_id']);
        } else {
            session()->remove('current_organization_id');
        }

        $this->users->update($user['id'], ['last_login_at' => date('Y-m-d H:i:s')]);

        return redirect()->to(site_url('dashboard'))->with('success', 'Sessao iniciada com sucesso.');
    }

    public function storeRegistration()
    {
        $data = [
            'name' => trim((string) $this->request->getPost('name')),
            'email' => trim((string) $this->request->getPost('email')),
            'password' => (string) $this->request->getPost('password'),
            'password_confirm' => (string) $this->request->getPost('password_confirm'),
            'organization_name' => trim((string) $this->request->getPost('organization_name')),
            'organization_slug' => trim((string) $this->request->getPost('organization_slug')),
            'organization_type' => trim((string) $this->request->getPost('organization_type')) ?: 'client',
            'country_code' => strtoupper(trim((string) $this->request->getPost('country_code'))),
            'website' => trim((string) $this->request->getPost('website')),
        ];

        if ($data['organization_slug'] === '') {
            $data['organization_slug'] = url_title($data['organization_name'], '-', true);
        } else {
            $data['organization_slug'] = url_title($data['organization_slug'], '-', true);
        }

        $rules = [
            'name' => 'required|min_length[3]|max_length[140]',
            'email' => 'required|valid_email|is_unique[users.email]',
            'password' => 'required|min_length[8]',
            'password_confirm' => 'required|matches[password]',
            'organization_name' => 'required|min_length[3]|max_length[160]',
            'organization_slug' => 'required|min_length[3]|max_length[120]|alpha_dash|is_unique[organizations.slug]',
            'organization_type' => 'required|in_list[issuer,client,partner,auditor]',
            'country_code' => 'permit_empty|exact_length[2]',
            'website' => 'permit_empty|max_length[190]',
        ];

        if (! $this->validateData($data, $rules)) {
            return redirect()->back()
                ->withInput()
                ->with('errors', $this->validator->getErrors())
                ->with('error', 'Revista os campos e tenta novamente.');
        }

        $db = db_connect();
        $db->transStart();

        $userId = $this->users->insert([
            'name' => $data['name'],
            'email' => $data['email'],
            'password_hash' => password_hash($data['password'], PASSWORD_DEFAULT),
            'role' => 'user',
            'status' => 'active',
        ], true);

        $organizationId = $this->organizations->insert([
            'name' => $data['organization_name'],
            'slug' => $data['organization_slug'],
            'organization_type' => $data['organization_type'],
            'country_code' => $data['country_code'] ?: null,
            'email' => $data['email'],
            'website' => $data['website'] ?: null,
            'status' => 'active',
        ], true);

        $this->memberships->insert([
            'organization_id' => $organizationId,
            'user_id' => $userId,
            'role' => 'owner',
            'status' => 'active',
            'joined_at' => date('Y-m-d H:i:s'),
        ]);

        $db->transComplete();

        if (! $db->transStatus()) {
            return redirect()->back()
                ->withInput()
                ->with('error', 'Nao foi possivel criar a conta da empresa.');
        }

        session()->regenerate();
        session()->set('auth_user', [
            'id' => $userId,
            'name' => $data['name'],
            'email' => $data['email'],
            'role' => 'user',
        ]);
        session()->set('current_organization_id', $organizationId);

        return redirect()->to(site_url('dashboard'))->with('success', 'Conta criada. Bem-vindo ao workspace da tua empresa.');
    }

    public function switchOrganization(int $organizationId)
    {
        $user = session()->get('auth_user');
        if (! $user) {
            return redirect()->to(site_url('login'));
        }

        if (($user['role'] ?? null) === 'admin') {
            $organization = $this->organizations->find($organizationId);
            if (! $organization) {
                return redirect()->back()->with('error', 'Empresa nao encontrada.');
            }

            session()->set('current_organization_id', $organizationId);

            return redirect()->back()->with('success', 'Empresa ativa alterada para ' . $organization['name'] . '.');
        }

        $membership = $this->memberships->findActiveMembership((int) $user['id'], $organizationId);
        if (! $membership) {
            return redirect()->back()->with('error', 'Nao tens acesso a essa empresa.');
        }

        session()->set('current_organization_id', $organizationId);

        return redirect()->back()->with('success', 'Empresa ativa alterada para ' . $membership['organization_name'] . '.');
    }

    public function updateAccount()
    {
        $userId = (int) $this->authUser()['id'];
        $user = $this->users->find($userId);
        if (! $user) {
            return redirect()->to(site_url('logout'))->with('error', 'Sessao invalida. Inicia sessão novamente.');
        }

        $data = [
            'name' => trim((string) $this->request->getPost('name')),
            'email' => trim((string) $this->request->getPost('email')),
            'password' => (string) $this->request->getPost('password'),
            'password_confirm' => (string) $this->request->getPost('password_confirm'),
        ];

        $rules = [
            'name' => 'required|min_length[3]|max_length[140]',
            'email' => 'required|valid_email|is_unique[users.email,id,' . $userId . ']',
            'password' => 'permit_empty|min_length[8]',
            'password_confirm' => 'permit_empty|matches[password]',
        ];

        if (! $this->validateData($data, $rules)) {
            return redirect()->back()
                ->withInput()
                ->with('errors', $this->validator->getErrors())
                ->with('error', 'Revista os dados da tua conta.');
        }

        if ($data['password'] !== '' && $data['password_confirm'] !== $data['password']) {
            return redirect()->back()
                ->withInput()
                ->with('error', 'A confirmação da password não coincide.');
        }

        $update = [
            'name' => $data['name'],
            'email' => $data['email'],
        ];

        if ($data['password'] !== '') {
            $update['password_hash'] = password_hash($data['password'], PASSWORD_DEFAULT);
        }

        $this->users->update($userId, $update);
        $freshUser = $this->users->find($userId);
        $this->refreshSessionUser($freshUser);

        return redirect()->to(site_url('account'))->with('success', 'A tua conta foi atualizada com sucesso.');
    }

    public function logout()
    {
        session()->remove('auth_user');
        session()->remove('current_organization_id');
        session()->destroy();

        return redirect()->to(site_url('login'))->with('success', 'Sessao terminada.');
    }

    private function refreshSessionUser(array $user): void
    {
        session()->set('auth_user', [
            'id' => $user['id'],
            'name' => $user['name'],
            'email' => $user['email'],
            'role' => $user['role'],
        ]);
    }
}

