<?php
namespace Modules\Contractors\Controllers;

use Core\Controller;
use Core\Auth;
use Modules\Contractors\Models\ContractorModel;

class ContractorController extends Controller {
    private ContractorModel $model;

    private const DOC_TYPES = ['CAC_status', 'CAC_form', 'utility_bill', 'tax_clearance', 'other'];

    public function __construct() {
        parent::__construct();
        $this->model = new ContractorModel();
    }

    public function index() {
        $this->requireAuth();
        $orgId = $this->scopedOrgId();
        $page = max(1, (int)$this->getGet('page', 1));
        $perPage = 20;
        $filters = [
            'search' => $this->getGet('search', ''),
            'status' => $this->getGet('status', ''),
        ];

        $contractors = $this->model->getAllForOrg($orgId, $filters, $page, $perPage);
        $total = $this->model->countForOrg($orgId, $filters);
        $stats = $this->model->getStats($orgId);

        $paginationData = [
            'current_page' => $page,
            'total_pages' => (int)ceil($total / $perPage),
            'total_items' => $total,
            'url_pattern' => APP_URL . '/contractors?' . http_build_query(array_filter($filters)) . '&page=',
        ];

        $this->render('contractors/index', [
            'contractors' => $contractors,
            'stats' => $stats,
            'filters' => $filters,
            'isPlatformView' => $orgId === null,
            'paginationData' => $paginationData,
        ]);
    }

    public function create() {
        $this->requireAuth();
        if (Auth::orgId() === null) {
            $this->setFlash('error', 'Contractors belong to an organization. Log in as an organization user to register one.');
            $this->redirect('/contractors');
        }
        $this->render('contractors/create');
    }

    public function store() {
        $this->requireAuth();
        if (!$this->validateCsrf()) {
            $this->setFlash('error', 'Invalid security token. Please try again.');
            $this->redirect('/contractors/create');
        }
        if (Auth::orgId() === null) {
            $this->setFlash('error', 'Contractors belong to an organization. Log in as an organization user to register one.');
            $this->redirect('/contractors');
        }

        $data = $this->buildContractorData($_POST);
        if (empty($data['company_name']) || empty($data['tin']) || empty($data['address']) ||
            empty($data['phone']) || empty($data['email']) || empty($data['contact_person_name']) ||
            empty($data['contact_person_phone']) || empty($data['contact_person_email'])) {
            $this->setFlash('error', 'Please fill in all required fields.');
            $this->redirect('/contractors/create');
        }

        $data['org_id'] = Auth::orgId();
        $data['created_by'] = Auth::id();
        $data['contractor_code'] = $this->model->generateContractorCode();

        $contractorId = $this->model->create($data);

        $this->storeUploadedDocuments($contractorId);

        $userFirstName = trim($_POST['user_first_name'] ?? '');
        $userLastName = trim($_POST['user_last_name'] ?? '');
        $userEmail = trim($_POST['user_email'] ?? '');
        if ($userFirstName && $userLastName && $userEmail) {
            $this->createPrimaryUser($contractorId, $data['company_name'], $userFirstName, $userLastName, $userEmail);
        }

        logAudit('contractor_created', 'contractors', 'contractor', $contractorId, null, $data);
        $this->setFlash('success', 'Contractor registered successfully. Awaiting approval.');
        $this->redirect('/contractors/' . $contractorId);
    }

    public function show($id) {
        $this->requireAuth();
        $contractor = $this->model->getWithDetails((int)$id);
        if (!$contractor || (int)$contractor['org_id'] !== (int)Auth::orgId()) {
            $this->setFlash('error', 'Contractor not found.');
            $this->redirect('/contractors');
        }

        $this->render('contractors/show', [
            'contractor' => $contractor,
            'stats' => $this->model->getContractorStats((int)$id),
            'documents' => $this->model->getDocuments((int)$id),
            'projects' => $this->model->getProjects((int)$id),
            'users' => $this->model->getUsers((int)$id),
            'invoices' => $this->model->getInvoices((int)$id),
        ]);
    }

    public function edit($id) {
        $this->requireAuth();
        $contractor = $this->model->getWithDetails((int)$id);
        if (!$contractor || (int)$contractor['org_id'] !== (int)Auth::orgId()) {
            $this->setFlash('error', 'Contractor not found.');
            $this->redirect('/contractors');
        }
        $this->render('contractors/create', ['contractor' => $contractor]);
    }

    public function update($id) {
        $this->requireAuth();
        if (!$this->validateCsrf()) {
            $this->setFlash('error', 'Invalid security token. Please try again.');
            $this->redirect('/contractors/' . $id . '/edit');
        }

        $contractor = $this->model->find((int)$id);
        if (!$contractor || (int)$contractor['org_id'] !== (int)Auth::orgId()) {
            $this->setFlash('error', 'Contractor not found.');
            $this->redirect('/contractors');
        }

        $data = $this->buildContractorData($_POST);
        $this->model->update((int)$id, $data);
        $this->storeUploadedDocuments((int)$id);

        logAudit('contractor_updated', 'contractors', 'contractor', (int)$id, $contractor, $data);
        $this->setFlash('success', 'Contractor updated successfully.');
        $this->redirect('/contractors/' . $id);
    }

    public function approve($id) {
        $this->requireAuth();
        $contractor = $this->model->find((int)$id);
        if (!$contractor || (int)$contractor['org_id'] !== (int)Auth::orgId()) {
            $this->setFlash('error', 'Contractor not found.');
            $this->redirect('/contractors');
        }
        $this->model->update((int)$id, ['is_approved' => 1]);
        logAudit('contractor_approved', 'contractors', 'contractor', (int)$id);
        $this->setFlash('success', 'Contractor approved.');
        $this->redirect('/contractors/' . $id);
    }

    public function suspend($id) {
        $this->requireAuth();
        $contractor = $this->model->find((int)$id);
        if (!$contractor || (int)$contractor['org_id'] !== (int)Auth::orgId()) {
            $this->setFlash('error', 'Contractor not found.');
            $this->redirect('/contractors');
        }
        $this->model->update((int)$id, ['is_active' => 0]);
        logAudit('contractor_suspended', 'contractors', 'contractor', (int)$id);
        $this->setFlash('success', 'Contractor suspended.');
        $this->redirect('/contractors/' . $id);
    }

    public function uploadDocument($id) {
        $this->requireAuth();
        $contractor = $this->model->find((int)$id);
        if (!$contractor || (int)$contractor['org_id'] !== (int)Auth::orgId()) {
            $this->setFlash('error', 'Contractor not found.');
            $this->redirect('/contractors');
        }
        $this->storeUploadedDocuments((int)$id);
        $this->setFlash('success', 'Document uploaded successfully.');
        $this->redirect('/contractors/' . $id);
    }

    public function deleteDocument($docId) {
        $this->requireAuth();
        $doc = $this->dbQueryOne("SELECT * FROM contractor_documents WHERE id = ?", [(int)$docId]);
        if (!$doc) {
            $this->setFlash('error', 'Document not found.');
            $this->redirect('/contractors');
        }
        $contractor = $this->model->find((int)$doc['contractor_id']);
        if (!$contractor || (int)$contractor['org_id'] !== (int)Auth::orgId()) {
            $this->setFlash('error', 'Document not found.');
            $this->redirect('/contractors');
        }
        $this->dbExecute("DELETE FROM contractor_documents WHERE id = ?", [(int)$docId]);
        $this->setFlash('success', 'Document deleted.');
        $this->redirect('/contractors/' . $doc['contractor_id']);
    }

    public function addUser($contractorId) {
        $this->requireAuth();
        if (!$this->validateCsrf()) {
            $this->setFlash('error', 'Invalid security token. Please try again.');
            $this->redirect('/contractors/' . $contractorId);
        }
        $contractor = $this->model->find((int)$contractorId);
        if (!$contractor || (int)$contractor['org_id'] !== (int)Auth::orgId()) {
            $this->setFlash('error', 'Contractor not found.');
            $this->redirect('/contractors');
        }

        $firstName = trim($_POST['first_name'] ?? '');
        $lastName = trim($_POST['last_name'] ?? '');
        $email = trim($_POST['email'] ?? '');
        if (!$firstName || !$lastName || !$email) {
            $this->setFlash('error', 'First name, last name, and email are required.');
            $this->redirect('/contractors/' . $contractorId);
        }

        $this->createPrimaryUser((int)$contractorId, $contractor['company_name'], $firstName, $lastName, $email, !empty($_POST['is_admin']));
        $this->setFlash('success', 'User added successfully.');
        $this->redirect('/contractors/' . $contractorId);
    }

    public function removeUser($contractorId, $userId) {
        $this->requireAuth();
        $contractor = $this->model->find((int)$contractorId);
        if (!$contractor || (int)$contractor['org_id'] !== (int)Auth::orgId()) {
            $this->setFlash('error', 'Contractor not found.');
            $this->redirect('/contractors');
        }
        $this->dbExecute("DELETE FROM contractor_users WHERE contractor_id = ? AND user_id = ?", [(int)$contractorId, (int)$userId]);
        $this->dbExecute("UPDATE users SET is_active = 0 WHERE id = ? AND entity_type = 'contractor_user' AND entity_id = ?", [(int)$userId, (int)$contractorId]);
        $this->setFlash('success', 'User removed.');
        $this->redirect('/contractors/' . $contractorId);
    }

    public function performance($contractorId) {
        $this->requireAuth();
        $this->json($this->model->getContractorStats((int)$contractorId));
    }

    private function buildContractorData(array $post): array {
        return [
            'company_name' => trim($post['company_name'] ?? ''),
            'tin' => trim($post['tin'] ?? ''),
            'address' => trim($post['address'] ?? ''),
            'city' => $post['city'] ?? null,
            'state' => $post['state'] ?? null,
            'country' => $post['country'] ?? 'Nigeria',
            'phone' => trim($post['phone'] ?? ''),
            'email' => trim($post['email'] ?? ''),
            'website' => normalizeUrl($post['website'] ?? null),
            'notes' => $post['notes'] ?? null,
            'contact_person_name' => trim($post['contact_name'] ?? ''),
            'contact_person_phone' => trim($post['contact_phone'] ?? ''),
            'contact_person_email' => trim($post['contact_email'] ?? ''),
            'bank_name' => $post['bank_name'] ?? null,
            'account_number' => $post['account_number'] ?? null,
            'account_name' => $post['account_name'] ?? null,
        ];
    }

    private function storeUploadedDocuments(int $contractorId): void {
        if (empty($_FILES['documents']) || empty($_FILES['documents']['name'][0])) {
            return;
        }
        $types = $_POST['document_types'] ?? [];
        $count = count($_FILES['documents']['name']);
        for ($i = 0; $i < $count; $i++) {
            if ($_FILES['documents']['error'][$i] !== UPLOAD_ERR_OK) {
                continue;
            }
            $fileInput = [
                'name' => $_FILES['documents']['name'][$i],
                'type' => $_FILES['documents']['type'][$i],
                'tmp_name' => $_FILES['documents']['tmp_name'][$i],
                'error' => $_FILES['documents']['error'][$i],
                'size' => $_FILES['documents']['size'][$i],
            ];
            $upload = $this->uploadFile($fileInput, 'contractor_docs');
            if (!$upload) {
                continue;
            }
            $type = $types[$i] ?? 'other';
            if (!in_array($type, self::DOC_TYPES, true)) {
                $type = 'other';
            }
            $this->dbExecute(
                "INSERT INTO contractor_documents (contractor_id, document_type, document_name, file_path, file_size, uploaded_by, created_at)
                 VALUES (?, ?, ?, ?, ?, ?, NOW())",
                [$contractorId, $type, $upload['name'], $upload['path'], $upload['size'], Auth::id()]
            );
        }
    }

    private function createPrimaryUser(int $contractorId, string $companyName, string $firstName, string $lastName, string $email, bool $isAdmin = true): void {
        $existing = $this->dbQueryOne("SELECT id FROM users WHERE email = ?", [$email]);
        if ($existing) {
            $userId = (int)$existing['id'];
        } else {
            $tempPassword = substr(bin2hex(random_bytes(6)), 0, 10);
            $userId = (int)$this->dbExecuteInsert(
                "INSERT INTO users (org_id, entity_type, entity_id, first_name, last_name, email, password, is_active, created_at, updated_at)
                 VALUES (?, 'contractor_user', ?, ?, ?, ?, ?, 1, NOW(), NOW())",
                [Auth::orgId(), $contractorId, $firstName, $lastName, $email, password_hash($tempPassword, PASSWORD_BCRYPT)]
            );

            $htmlBody = "<p>Hello {$firstName},</p><p>An account has been created for you to access {$companyName}'s projects on " . APP_NAME . ".</p>" .
                "<p>Email: {$email}<br>Temporary Password: {$tempPassword}</p>" .
                "<p><a href=\"" . APP_URL . "/login\">Login here</a> and change your password after signing in.</p>";
            sendEmail($email, $firstName . ' ' . $lastName, 'Your ' . APP_NAME . ' account', $htmlBody);
        }

        $exists = $this->dbQueryOne("SELECT id FROM contractor_users WHERE contractor_id = ? AND user_id = ?", [$contractorId, $userId]);
        if (!$exists) {
            $this->dbExecute(
                "INSERT INTO contractor_users (contractor_id, user_id, is_admin, created_at) VALUES (?, ?, ?, NOW())",
                [$contractorId, $userId, $isAdmin ? 1 : 0]
            );
        }
        createNotification($userId, 'account_created', 'Welcome to ' . APP_NAME, 'Your contractor account has been created.');
    }

    private function dbExecuteInsert(string $sql, array $params): int {
        $stmt = $this->db->prepare($sql);
        $stmt->execute($params);
        return (int)$this->db->lastInsertId();
    }
}
