<?php
declare(strict_types=1);

namespace App\Controllers;

use App\Core\Auth;
use App\Core\Request;
use App\Core\Validator;
use App\Models\Account;
use App\Models\AuditLog;
use App\Models\JobNote;
use App\Models\ServiceJob;
use App\Models\Task;
use App\Models\User;
use App\Services\CommerceService;
use App\Services\RecordService;

final class JobController extends BaseController
{
    public function index(Request $request): void
    {
        $this->requireModule('service_jobs');
        $status = (string) ($_GET['status'] ?? 'open');
        if (!in_array($status, ['all', 'open', 'in_progress', 'done', 'cancelled'], true)) {
            $status = 'open';
        }
        $source = (string) ($_GET['source'] ?? 'all');
        if (!in_array($source, ['all', 'staff', 'customer', 'deal_won'], true)) {
            $source = 'all';
        }
        $page = $this->page();
        $scope = has_role('manager') ? null : Auth::instance()->id();
        $assigned = (int) ($_GET['assigned'] ?? 0);
        $assigneeFilter = $scope;
        if ($scope === null && $assigned > 0) {
            $assigneeFilter = $assigned;
        }
        $result = ServiceJob::paginate($assigneeFilter, $status, $this->q(), $page, 20, $source);
        view('jobs/index', [
            'title' => 'Service jobs',
            'rows' => $result['rows'],
            'total' => $result['total'],
            'page' => $page,
            'pages' => max(1, (int) ceil($result['total'] / 20)),
            'q' => $this->q(),
            'status' => $status,
            'source' => $source,
            'assigned' => $assigned,
            'showAssigned' => $scope === null,
            'counts' => ServiceJob::counts($assigneeFilter),
            'accounts' => Account::allForSelect(),
            'assignees' => User::servicePeople((int) Auth::instance()->tenantId()),
            'notifications' => $this->notifications(),
        ]);
    }

    public function show(Request $request): void
    {
        $this->requireModule('service_jobs');
        $row = ServiceJob::detail((int) $request->param('id'));
        if (!$row) {
            flash('error', 'Job not found.');
            redirect('jobs');
        }
        if (!has_role('manager') && (int) $row['assignee_id'] !== (int) Auth::instance()->id()) {
            flash('error', 'This job is not assigned to you.');
            redirect('jobs');
        }
        view('jobs/show', [
            'title' => $row['subject'] ?: $row['number'],
            'row' => $row,
            'notes' => JobNote::forJob((int) $row['id']),
            'tasks' => Task::forRelated('account', (int) $row['account_id']),
            'assignees' => User::servicePeople((int) Auth::instance()->tenantId()),
            'notifications' => $this->notifications(),
        ]);
    }

    public function store(Request $request): void
    {
        $this->requireModule('service_jobs');
        $this->verifyCsrf($request);
        $data = $request->all();
        $v = (new Validator())->required($data, ['account_id' => 'Account', 'subject' => 'Subject']);
        if ($v->fails()) {
            $this->fail($v);
        }
        $account = Account::find((int) $data['account_id']);
        if (!$account) {
            json_out(['ok' => false, 'error' => 'Account not found.'], 404);
        }
        $id = ServiceJob::create([
            'account_id' => (int) $account['id'],
            'opportunity_id' => null,
            'assignee_id' => !empty($data['assignee_id']) ? (int) $data['assignee_id'] : Auth::instance()->id(),
            'number' => CommerceService::tempNumber(),
            'subject' => $data['subject'],
            'body' => $data['body'] ?? '',
            'status' => 'open',
            'source' => 'staff',
        ]);
        CommerceService::assignNumber('service_jobs', $id, 'JOB-');
        RecordService::logActivity('visit', 'Service job opened', (string) $data['subject'], 'account', (int) $account['id']);
        AuditLog::write('job.create', 'job', $id);
        json_out(['ok' => true, 'id' => $id, 'redirect' => url('jobs/' . $id)]);
    }

    public function update(Request $request): void
    {
        $this->requireModule('service_jobs');
        $this->verifyCsrf($request);
        $row = ServiceJob::find((int) $request->param('id'));
        if (!$row) {
            json_out(['ok' => false, 'error' => 'Not found.'], 404);
        }
        $st = (string) $request->input('status', $row['status']);
        if (!in_array($st, ['open', 'in_progress', 'done', 'cancelled'], true)) {
            json_out(['ok' => false, 'error' => 'Invalid status.'], 422);
        }
        ServiceJob::update((int) $row['id'], [
            'status' => $st,
            'assignee_id' => !empty($request->input('assignee_id')) ? (int) $request->input('assignee_id') : $row['assignee_id'],
            'subject' => $request->input('subject') ?: $row['subject'],
            'body' => $request->input('body', $row['body']),
        ]);
        AuditLog::write('job.update', 'job', (int) $row['id']);
        json_out(['ok' => true]);
    }

    public function note(Request $request): void
    {
        $this->requireModule('service_jobs');
        $this->verifyCsrf($request);
        $row = ServiceJob::find((int) $request->param('id'));
        if (!$row) {
            json_out(['ok' => false, 'error' => 'Not found.'], 404);
        }
        $body = trim((string) $request->input('body', ''));
        if ($body === '') {
            json_out(['ok' => false, 'error' => 'Write what was done.'], 422);
        }
        JobNote::create([
            'job_id' => (int) $row['id'],
            'user_id' => Auth::instance()->id(),
            'body' => $body,
        ]);
        RecordService::logActivity('visit', 'Job note', $body, 'account', (int) $row['account_id']);
        AuditLog::write('job.note', 'job', (int) $row['id']);
        json_out(['ok' => true, 'message' => 'Note saved on the job.']);
    }
}
