<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Core\Auth;
use App\Core\Csrf;
use App\Core\DB;
use App\Core\Request;
use App\Core\Response;
use App\Core\AppBootstrap;
use App\Repositories\PartyRepository;
use App\Services\PartyService;
use App\Modules\Parties\Application\Services\PartiesRouteContext;
use Throwable;

final class PartyController
{
    private \PDO $pdo;
    private PartyRepository $parties;
    private PartyService $service;
    private PartiesRouteContext $routeContext;

    public function __construct()
    {
        $this->pdo = DB::pdo();
        $this->parties = new PartyRepository($this->pdo);
        $this->service = new PartyService($this->pdo, $this->parties);
        $this->routeContext = new PartiesRouteContext();
    }

    public function handle(?string $forcedType = null): void
    {
        Auth::requireLogin();
        AppBootstrap::bootParties($this->pdo);
        require_view_parties();

        $q = trim((string) Request::get('q', ''));
        $type = trim((string) ($forcedType ?? Request::get('type', 'all')));
        if ($type === 'customers') {
            $type = 'customer';
        } elseif ($type === 'suppliers') {
            $type = 'supplier';
        }
        if (!in_array($type, ['all', 'customer', 'supplier', 'both'], true)) {
            $type = 'all';
        }
        $editId = (int) Request::get('edit', 0);
        $page = max(1, (int) Request::get('page', 1));
        $perPage = 25;

        if (Request::isPost()) {
            try {
                $this->handlePost($type, $q, $page);
                return;
            } catch (Throwable $e) {
                if ($this->pdo->inTransaction()) {
                    $this->pdo->rollBack();
                }
                Response::flash('danger', $e->getMessage() ?: 'تعذر حفظ الطرف. تأكد من عدم تكرار الكود.');
                $id = (int) Request::post('id', 0);
                $fallbackBase = $this->routeContext->listPath($type);
                $suffix = (string) Request::post('action', '') === 'update' && $id > 0 ? ((str_contains($fallbackBase, '?') ? '&' : '?') . 'edit=' . $id) : '';
                Response::redirect($fallbackBase . $suffix);
                return;
            }
        }

        $editParty = null;
        if ($editId > 0 && can_manage_parties()) {
            $editParty = $this->parties->findById($editId) ?: null;
        }

        $totalRows = $this->parties->countFiltered($type, $q);
        $totalPages = max(1, (int) ceil($totalRows / $perPage));
        if ($page > $totalPages) {
            $page = $totalPages;
        }
        $offset = ($page - 1) * $perPage;
        $parties = $this->parties->paginateFiltered($type, $q, $perPage, $offset);

        Response::view('pages/parties/index', [
            'parties' => $parties,
            'q' => $q,
            'type' => $type,
            'edit_party' => $editParty,
            'page' => $page,
            'per_page' => $perPage,
            'total_rows' => $totalRows,
            'total_pages' => $totalPages,
            'base_index_url' => $this->routeContext->listPath($type),
            'party_view_base_url' => $this->routeContext->viewPath(0),
            'party_edit_base_url' => $this->routeContext->editPath(0, $type),
        ]);
    }

    private function handlePost(string $type, string $q, int $page): void
    {
        $action = (string) Request::post('action', '');
        if (!in_array($action, ['create', 'update', 'delete'], true)) {
            return;
        }

        if (!can_manage_parties()) {
            http_response_code(403);
            Response::view('pages/dashboard', ['error' => 'ليس لديك صلاحية لإضافة/تعديل الأطراف.']);
            return;
        }

        Csrf::verify();
        $id = (int) Request::post('id', 0);

        if ($action === 'delete') {
            $this->service->delete($id);
            audit_log('PARTY_DELETE', 'parties', $id, null);
            Response::flash('success', 'تم حذف الطرف');
            Response::redirect($this->buildIndexUrl($type, $q, $page));
            return;
        }

        if ($action === 'create') {
            $newId = $this->service->create(Request::all(), current_user_id() ? (int) current_user_id() : null);
            $name = trim((string) Request::post('name', ''));
            audit_log('PARTY_CREATE', 'parties', $newId, [
                'name' => $name,
                'is_customer' => !empty(Request::post('is_customer')) ? 1 : 0,
                'is_supplier' => !empty(Request::post('is_supplier')) ? 1 : 0,
            ]);
            Response::flash('success', 'تم إضافة الطرف');
            Response::redirect($this->buildIndexUrl($type, $q, $page));
            return;
        }

        $this->service->update($id, Request::all());
        $name = trim((string) Request::post('name', ''));
        audit_log('PARTY_UPDATE', 'parties', $id, [
            'name' => $name,
            'is_customer' => !empty(Request::post('is_customer')) ? 1 : 0,
            'is_supplier' => !empty(Request::post('is_supplier')) ? 1 : 0,
        ]);
        Response::flash('success', 'تم حفظ التعديلات');
        Response::redirect($this->buildIndexUrl($type, $q, $page));
    }

    private function buildIndexUrl(string $type, string $q, int $page): string
    {
        $qs = [];
        if ($q !== '') {
            $qs['q'] = $q;
        }
        if ($page > 1) {
            $qs['page'] = $page;
        }

        $base = $this->routeContext->listPath($type);
        if ($type === 'all' && !$this->routeContext->isPartiesRoute()) {
            $qs = array_filter(['type' => $type !== 'all' ? $type : null] + $qs, static fn ($v) => $v !== null && $v !== '');
        }

        return $base . ($qs ? ((str_contains($base, '?') ? '&' : '?') . http_build_query($qs)) : '');
    }
}
