<?php

namespace App\Controllers\Api\V1;

use App\Controllers\BaseController;
use App\Models\AgencyModel;
use App\Repositories\AgencyRepository;
use App\Services\Agency\RecruiterManagementService;

class AgencyController extends BaseController
{
    private AgencyRepository $agencies;
    private RecruiterManagementService $recruiters;

    public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
    {
        parent::initController($request, $response, $logger);
        $this->agencies   = new AgencyRepository(new AgencyModel());
        $this->recruiters = new RecruiterManagementService();
    }

    // --- Public ---

    public function show(string $slug)
    {
        $agency = $this->agencies->findBySlug($slug);
        if (! $agency || ! $agency->isActive()) {
            return $this->jsonError([['code' => 'NOT_FOUND', 'message' => 'Agency not found.']], 404);
        }

        $reviews = \Config\Database::connect()->table('company_reviews')
            ->where('agency_id', $agency->id)->where('status', 'approved')
            ->orderBy('created_at', 'DESC')->limit(20)->get()->getResultArray();

        $avgRating = \Config\Database::connect()->table('company_reviews')
            ->selectAvg('rating')->where('agency_id', $agency->id)->where('status', 'approved')
            ->get()->getRow()->rating ?? null;

        return $this->jsonSuccess([
            'agency'         => $agency->toArray(),
            'average_rating' => $avgRating !== null ? round((float) $avgRating, 1) : null,
            'reviews'        => $reviews,
        ]);
    }

    public function submitReview(string $slug)
    {
        $user = $this->currentUser();
        if (! $user->isCandidate()) {
            return $this->jsonError([['code' => 'FORBIDDEN', 'message' => 'Only candidates can submit reviews.']], 403);
        }

        $agency = $this->agencies->findBySlug($slug);
        if (! $agency) {
            return $this->jsonError([['code' => 'NOT_FOUND', 'message' => 'Agency not found.']], 404);
        }

        $rules = [
            'rating'      => 'required|is_natural_no_zero|greater_than[0]|less_than[6]',
            'title'       => 'permit_empty|max_length[150]',
            'review_text' => 'permit_empty|max_length[2000]',
        ];
        if (! $this->validate($rules)) {
            return $this->jsonValidationError($this->validator->getErrors());
        }

        $input = $this->request->getJSON(true);

        \Config\Database::connect()->table('company_reviews')->insert([
            'agency_id'        => $agency->id,
            'reviewer_user_id' => $user->id,
            'rating'           => $input['rating'],
            'title'            => $input['title'] ?? null,
            'review_text'      => $input['review_text'] ?? null,
            'status'           => 'pending', // moderated by Super Admin before going public
            'created_at'       => date('Y-m-d H:i:s'),
        ]);

        return $this->jsonSuccess(['message' => 'Review submitted and pending moderation.'], [], 201);
    }

    // --- Agency Owner: own agency ---

    public function uploadLogo()
    {
        return $this->uploadAgencyImage('logo_path', 'logos');
    }

    public function uploadCover()
    {
        return $this->uploadAgencyImage('cover_image_path', 'covers');
    }

    private function uploadAgencyImage(string $column, string $subfolder)
    {
        $user = $this->currentUser();
        if (! $user->agency_id) {
            return $this->jsonError([['code' => 'NO_AGENCY', 'message' => 'This account has no associated agency.']], 404);
        }

        $file = $this->request->getFile('image');
        if (! $file) {
            return $this->jsonError([['code' => 'FILE_MISSING', 'message' => 'No file uploaded under field "image".']], 400);
        }

        try {
            $uploader = new \App\Services\Support\ImageUploadService();
            $stored = $uploader->validateAndStore($file, $subfolder);
        } catch (\InvalidArgumentException $e) {
            return $this->jsonError([['code' => 'INVALID_FILE', 'message' => $e->getMessage()]], 422);
        } catch (\RuntimeException $e) {
            return $this->jsonError([['code' => 'UPLOAD_FAILED', 'message' => $e->getMessage()]], 500);
        }

        $existing = $this->agencies->find($user->agency_id);
        (new \App\Services\Support\ImageUploadService())->delete($existing->{$column});

        $this->agencies->update($user->agency_id, [$column => $stored['relative_path']]);

        return $this->jsonSuccess([$column => base_url($stored['relative_path'])]);
    }

    public function me()
    {
        $user = $this->currentUser();
        if (! $user->agency_id) {
            return $this->jsonError([['code' => 'NO_AGENCY', 'message' => 'This account has no associated agency.']], 404);
        }
        $agency = $this->agencies->find($user->agency_id);
        return $this->jsonSuccess(['agency' => $agency->toArray()]);
    }

    public function updateMe()
    {
        $user = $this->currentUser();
        $this->guardAgencyOwner($user);

        $rules = [
            'company_name' => 'permit_empty|max_length[150]',
            'website'      => 'permit_empty|valid_url_strict',
            'email'        => 'permit_empty|valid_email',
        ];
        if (! $this->validate($rules)) {
            return $this->jsonValidationError($this->validator->getErrors());
        }

        $allowed = array_intersect_key($this->request->getJSON(true), array_flip([
            'company_name', 'website', 'email', 'phone', 'industry', 'company_size',
            'description', 'services', 'social_links', 'registration_number', 'tax_number', 'address',
        ]));

        if (isset($allowed['social_links']) && is_array($allowed['social_links'])) {
            $allowed['social_links'] = json_encode($allowed['social_links']);
        }

        $this->agencies->update($user->agency_id, $allowed);

        return $this->jsonSuccess(['agency' => $this->agencies->find($user->agency_id)]);
    }

    // --- Agency Owner: team management ---

    public function listTeam()
    {
        $user = $this->currentUser();
        $this->guardAgencyOwner($user);

        return $this->jsonSuccess(['team' => $this->recruiters->listTeam($user->agency_id)]);
    }

    public function inviteRecruiter()
    {
        $user = $this->currentUser();
        $this->guardAgencyOwner($user);

        $rules = [
            'email' => 'required|valid_email',
            'role'  => 'permit_empty|in_list[recruiter,support_staff]',
        ];
        if (! $this->validate($rules)) {
            return $this->jsonValidationError($this->validator->getErrors());
        }

        $input = $this->request->getJSON(true);

        try {
            $result = $this->recruiters->invite($user->agency_id, $user->id, $input['email'], $input['role'] ?? 'recruiter');
        } catch (\InvalidArgumentException $e) {
            return $this->jsonError([['code' => 'INVITE_FAILED', 'message' => $e->getMessage()]], 422);
        }

        return $this->jsonSuccess([
            'message'        => 'Invitation sent.',
            'invitation_url' => base_url('accept-invitation/' . $result['token']),
        ], [], 201);
    }

    public function removeRecruiter(int $userId)
    {
        $user = $this->currentUser();
        $this->guardAgencyOwner($user);

        try {
            $this->recruiters->remove($user->agency_id, $userId, $user->id);
        } catch (\InvalidArgumentException $e) {
            return $this->jsonError([['code' => 'REMOVE_FAILED', 'message' => $e->getMessage()]], 422);
        }

        return $this->jsonSuccess(['message' => 'Recruiter removed.']);
    }

    public function setRecruiterPermission(int $userId)
    {
        $user = $this->currentUser();
        $this->guardAgencyOwner($user);

        $rules = [
            'permission_id' => 'required|is_natural_no_zero',
            'effect'        => 'required|in_list[grant,revoke]',
        ];
        if (! $this->validate($rules)) {
            return $this->jsonValidationError($this->validator->getErrors());
        }

        $input = $this->request->getJSON(true);

        try {
            $this->recruiters->setPermissionOverride($user->agency_id, $userId, $input['permission_id'], $input['effect'], $user->id);
        } catch (\InvalidArgumentException $e) {
            return $this->jsonError([['code' => 'PERMISSION_UPDATE_FAILED', 'message' => $e->getMessage()]], 422);
        }

        return $this->jsonSuccess(['message' => 'Permission updated.']);
    }

    private function guardAgencyOwner($user): void
    {
        if (! $user->isAgencyOwner()) {
            throw new \App\Exceptions\ForbiddenException('This action is only available to the Agency Owner.');
        }
    }
}
