<?php
require_once __DIR__ . '/../Core.php';
require_once __DIR__ . '/../models/Contact.php';
require_once __DIR__ . '/../models/Segment.php';
require_once __DIR__ . '/../models/Suppression.php';
require_once __DIR__ . '/../models/CustomField.php';
require_once __DIR__ . '/../models/ConsentLog.php';
require_once __DIR__ . '/../models/ContactTask.php';
require_once __DIR__ . '/../models/ContactNote.php';
require_once __DIR__ . '/../models/User.php';
require_once __DIR__ . '/../models/Account.php';
require_once __DIR__ . '/../models/Pipeline.php';
require_once __DIR__ . '/../models/Reminder.php';
require_once __DIR__ . '/../models/ContactList.php';
require_once __DIR__ . '/../models/Message.php';

class ContactsController extends Controller
{
    public function index(): void
    {
        require_permission('contacts.view');
        $q = trim($_GET['q'] ?? '');
        $channel = $_GET['channel'] ?? 'all';
        $segmentId = (int)($_GET['segment_id'] ?? 0) ?: null;
        $page = max(1, (int)($_GET['page'] ?? 1));
        $result = (new Contact())->search($q, $channel, $page, 20, $segmentId);
        $segmentModel = new Segment();
        $segments = $segmentModel->all();
        foreach ($segments as &$segment) {
            $segment['member_count'] = $segmentModel->countMembers((int)$segment['id']);
        }
        unset($segment);
        $this->view('contacts/index', [
            'contacts' => $result['data'],
            'meta' => $result['meta'],
            'filters' => ['q' => $q, 'channel' => $channel, 'segment_id' => $segmentId],
            'segments' => $segments,
            'customFields' => (new CustomField())->all(),
            'users' => (new User())->all(),
            'accounts' => (new Account())->all(),
            'pipelines' => (new Pipeline())->all(),
            'contactLists' => (new ContactList())->all(),
            'contactCounts' => (new Contact())->counts(),
        ]);
    }

    public function show(): void
    {
        require_permission('contacts.view');
        $id = (int)($_GET['id'] ?? 0);
        $contactModel = new Contact();
        $contact = $contactModel->find($id);
        if (!$contact) {
            http_response_code(404);
            exit('Contact not found.');
        }

        $suppression = new Suppression();
        $customFieldModel = new CustomField();
        $messageModel = new Message();

        $smsConversations = $messageModel->contactConversations($contact, 'sms', 30);
        $emailConversations = $messageModel->contactConversations($contact, 'email', 30);

        $commTab = trim((string)($_GET['comm_tab'] ?? ($_GET['tab'] ?? '')));
        if ($commTab === '') {
            $commTab = !empty($contact['email']) ? 'email' : 'sms';
        }
        if ($commTab === 'sms' && empty($contact['phone']) && !empty($contact['email'])) {
            $commTab = 'email';
        }
        if ($commTab === 'email' && empty($contact['email']) && !empty($contact['phone'])) {
            $commTab = 'sms';
        }
        if (!in_array($commTab, ['sms', 'email'], true)) {
            $commTab = !empty($contact['email']) ? 'email' : 'sms';
        }

        $selectedSmsKey = trim((string)($_GET['sms_conversation'] ?? ($_GET['sms_thread'] ?? '')));
        if ($selectedSmsKey === '' && !empty($smsConversations[0]['conversation_key'])) {
            $selectedSmsKey = (string)$smsConversations[0]['conversation_key'];
        }
        $selectedEmailKey = trim((string)($_GET['email_conversation'] ?? ($_GET['email_thread'] ?? '')));
        if ($selectedEmailKey === '' && !empty($emailConversations[0]['conversation_key'])) {
            $selectedEmailKey = (string)$emailConversations[0]['conversation_key'];
        }

        $selectedSmsThread = null;
        foreach ($smsConversations as $row) {
            if (($row['conversation_key'] ?? '') === $selectedSmsKey) {
                $selectedSmsThread = $row;
                break;
            }
        }
        $selectedEmailThread = null;
        foreach ($emailConversations as $row) {
            if (($row['conversation_key'] ?? '') === $selectedEmailKey) {
                $selectedEmailThread = $row;
                break;
            }
        }

        $suppressed = [
            'sms' => !empty($contact['phone']) ? $suppression->isSuppressed('sms', (string)$contact['phone']) : false,
            'email' => !empty($contact['email']) ? $suppression->isSuppressed('email', (string)$contact['email']) : false,
        ];

        $this->view('contacts/show', [
            'contact' => $contact,
            'summary' => $contactModel->engagementSummary($id),
            'timeline' => $contactModel->activityTimeline($id),
            'suppressed' => $suppressed,
            'suppressionEntries' => $suppression->forContact($id),
            'customFields' => $customFieldModel->all(),
            'customValues' => $customFieldModel->valuesForContact($id),
            'consentLogs' => (new ConsentLog())->forContact($id),
            'tasks' => (new ContactTask())->forContact($id),
            'notes' => (new ContactNote())->forContact($id),
            'reminders' => (new Reminder())->forContact($id),
            'users' => (new User())->all(),
            'accounts' => (new Account())->all(),
            'pipelines' => (new Pipeline())->all(),
            'contactLists' => (new ContactList())->all(),
            'contactCounts' => (new Contact())->counts(),
            'commTab' => $commTab,
            'smsConversations' => $smsConversations,
            'emailConversations' => $emailConversations,
            'selectedSmsThread' => $selectedSmsThread,
            'selectedEmailThread' => $selectedEmailThread,
            'smsThreadMessages' => $selectedSmsThread ? $messageModel->contactThread($contact, 'sms', $selectedSmsKey, 250) : [],
            'emailThreadMessages' => $selectedEmailThread ? $messageModel->contactThread($contact, 'email', $selectedEmailKey, 250) : [],
            'recentCampaigns' => $messageModel->recentCampaignsForContact($id, 8),
        ]);
    }

    public function save(): void
    {
        require_permission('contacts.manage');
        verify_csrf();
        try {
            $contactModel = new Contact();
            $listId = (int)($_POST['add_to_list_id'] ?? 0);
            if ($listId > 0) {
                $list = (new ContactList())->find($listId);
                if (!$list) {
                    throw new RuntimeException('The selected list was not found.');
                }
            }

            $result = $contactModel->createOrReuse($_POST);
            $contactId = (int)$result['id'];
            $matchedBy = $result['matched_by'] ? strtoupper((string)$result['matched_by']) : 'EMAIL/PHONE';

            if ($listId > 0) {
                (new ContactList())->addMember($listId, $contactId);
                flash('success', $result['created']
                    ? 'Contact saved and added to the selected list.'
                    : 'Existing contact matched by ' . $matchedBy . '; no duplicate was created. The contact was refreshed and added to the selected list.');
            } else {
                flash('success', $result['created']
                    ? 'Contact saved successfully.'
                    : 'Existing contact matched by ' . $matchedBy . '; no duplicate was created. Missing details were refreshed.');
            }
        } catch (Throwable $e) {
            flash('error', $e->getMessage());
        }
        redirect('contacts/index');
    }

    public function import(): void
    {
        require_permission('contacts.manage');
        verify_csrf();
        try {
            $file = upload_file($_FILES['csv_file'] ?? [], ['csv']);
            if (!$file) {
                throw new RuntimeException('Please upload a CSV file.');
            }
            $stats = (new Contact())->importCsv(uploaded_file_path($file));
            flash('success', 'Processed ' . (int)$stats['processed'] . ' contacts: ' . (int)$stats['new'] . ' new, ' . (int)$stats['existing'] . ' existing reused, ' . (int)$stats['skipped'] . ' skipped.');
        } catch (Throwable $e) {
            flash('error', $e->getMessage());
        }
        redirect('contacts/index');
    }

    public function exportCsv(): void
    {
        require_permission('messages.export');
        $q = trim($_GET['q'] ?? '');
        $channel = $_GET['channel'] ?? 'all';
        $segmentId = (int)($_GET['segment_id'] ?? 0) ?: null;
        $rows = (new Contact())->exportRows($q, $channel, $segmentId);
        header('Content-Type: text/csv');
        header('Content-Disposition: attachment; filename="contacts_export.csv"');
        $out = fopen('php://output', 'w');
        fputcsv($out, ['ID','First Name','Last Name','Phone','Email','Company','Tags','Timezone','Lifecycle Stage','Score','Unsubscribed SMS','Unsubscribed Email']);
        foreach ($rows as $row) {
            fputcsv($out, [$row['id'], $row['first_name'], $row['last_name'], $row['phone'], $row['email'], $row['company'], $row['tags'], $row['timezone'] ?? '', $row['lifecycle_stage'] ?? '', $row['score'] ?? 0, $row['unsubscribed_sms'], $row['unsubscribed_email']]);
        }
        fclose($out);
        exit;
    }

    public function delete(): void
    {
        require_permission('contacts.delete');
        $id = (int)($_GET['id'] ?? 0);
        if ($id) {
            (new Contact())->delete($id);
            flash('success', 'Contact deleted.');
        }
        redirect('contacts/index');
    }

    public function saveSegment(): void
    {
        require_permission('segments.manage');
        verify_csrf();
        $id = (new Segment())->create($_POST);
        audit_log('segment.created', 'segment', $id, ['name' => $_POST['name'] ?? null]);
        flash('success', 'Segment saved.');
        redirect('contacts/index');
    }

    public function deleteSegment(): void
    {
        require_permission('segments.manage');
        $id = (int)($_GET['id'] ?? 0);
        if ($id) {
            (new Segment())->delete($id);
            audit_log('segment.deleted', 'segment', $id);
            flash('success', 'Segment deleted.');
        }
        redirect('contacts/index');
    }

    public function saveContactList(): void
    {
        require_permission('contacts.manage');
        verify_csrf();
        $id = (new ContactList())->create([
            'name' => $_POST['name'] ?? '',
            'channel' => $_POST['channel'] ?? 'both',
            'description' => $_POST['description'] ?? '',
            'created_by' => current_user()['id'] ?? null,
        ]);
        audit_log('contact_list.created', 'contact_list', $id, ['name' => $_POST['name'] ?? '']);
        flash('success', 'Contact list saved.');
        redirect('contacts/index');
    }

    public function importContactList(): void
    {
        require_permission('contacts.manage');
        verify_csrf();
        $listId = (int)($_POST['list_id'] ?? 0);
        try {
            $file = upload_file($_FILES['csv_file'] ?? [], ['csv']);
            if (!$file) {
                throw new RuntimeException('Please upload a CSV file.');
            }
            $stats = (new ContactList())->importCsv($listId, uploaded_file_path($file));
            audit_log('contact_list.imported', 'contact_list', $listId, $stats);
            flash('success', 'Processed ' . (int)$stats['processed'] . ' list rows: ' . (int)$stats['new'] . ' new contacts, ' . (int)$stats['existing'] . ' existing reused, ' . (int)$stats['skipped'] . ' skipped.');
        } catch (Throwable $e) {
            flash('error', $e->getMessage());
        }
        redirect('contacts/index');
    }

    public function deleteContactList(): void
    {
        require_permission('contacts.manage');
        $id = (int)($_GET['id'] ?? 0);
        if ($id) {
            (new ContactList())->delete($id);
            audit_log('contact_list.deleted', 'contact_list', $id);
            flash('success', 'Contact list deleted.');
        }
        redirect('contacts/index');
    }

    public function saveCustomValues(): void
    {
        require_permission('contacts.manage');
        verify_csrf();
        $contactId = (int)($_POST['contact_id'] ?? 0);
        (new CustomField())->saveValuesForContact($contactId, $_POST['custom'] ?? []);
        audit_log('contact.custom_fields.updated', 'contact', $contactId);
        flash('success', 'Custom field values saved.');
        $this->redirectToContact($contactId, trim((string)($_POST['comm_tab'] ?? '')) ?: null);
    }

    public function addConsent(): void
    {
        require_permission('contacts.manage');
        verify_csrf();
        $contactId = (int)($_POST['contact_id'] ?? 0);
        $channel = ($_POST['channel'] ?? 'email') === 'sms' ? 'sms' : 'email';
        $status = $_POST['status'] ?? 'opt_in';
        (new ConsentLog())->create([
            'contact_id' => $contactId,
            'channel' => $channel,
            'status' => $status,
            'source' => trim($_POST['source'] ?? 'manual'),
            'proof_note' => trim($_POST['proof_note'] ?? ''),
            'ip_address' => $_SERVER['REMOTE_ADDR'] ?? null,
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? null,
            'created_by' => current_user()['id'] ?? null,
        ]);
        $contact = (new Contact())->find($contactId);
        if ($contact) {
            $address = $channel === 'sms' ? (string)($contact['phone'] ?? '') : (string)($contact['email'] ?? '');
            (new Contact())->setUnsubscribed($channel, $address, $status !== 'opt_in');
            if ($status === 'opt_in') {
                (new Suppression())->removeByAddress($channel, $address);
            } else {
                (new Suppression())->add($channel, $address, 'unsubscribe', $contactId, null);
            }
        }
        audit_log('contact.consent.logged', 'contact', $contactId, ['channel' => $channel, 'status' => $status]);
        flash('success', 'Consent record added.');
        $this->redirectToContact($contactId, trim((string)($_POST['comm_tab'] ?? '')) ?: null);
    }

    public function unsubscribe(): void
    {
        require_permission('contacts.manage');
        verify_csrf();
        $contactId = (int)($_POST['contact_id'] ?? 0);
        $channel = ($_POST['channel'] ?? 'email') === 'sms' ? 'sms' : 'email';
        $contact = (new Contact())->find($contactId);
        if (!$contact) {
            flash('error', 'Contact not found.');
            redirect('contacts/index');
        }
        $address = $channel === 'sms' ? (string)($contact['phone'] ?? '') : (string)($contact['email'] ?? '');
        if ($address === '') {
            flash('error', 'This contact does not have a ' . strtoupper($channel) . ' address to suppress.');
            $this->redirectToContact($contactId, trim((string)($_POST['comm_tab'] ?? '')) ?: null);
        }
        (new Contact())->setUnsubscribed($channel, $address, true);
        (new Suppression())->add($channel, $address, trim((string)($_POST['reason'] ?? 'manual opt-out')) ?: 'manual opt-out', $contactId, null);
        (new ConsentLog())->create([
            'contact_id' => $contactId,
            'channel' => $channel,
            'status' => 'opt_out',
            'source' => 'manual',
            'proof_note' => trim((string)($_POST['reason'] ?? 'Manual unsubscribe from contact profile')),
            'ip_address' => $_SERVER['REMOTE_ADDR'] ?? null,
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? null,
            'created_by' => current_user()['id'] ?? null,
        ]);
        audit_log('contact.unsubscribed', 'contact', $contactId, ['channel' => $channel, 'address' => $address]);
        flash('success', strtoupper($channel) . ' unsubscribed for this contact.');
        $this->redirectToContact($contactId, trim((string)($_POST['comm_tab'] ?? '')) ?: null);
    }

    public function resubscribe(): void
    {
        require_permission('contacts.manage');
        verify_csrf();
        $contactId = (int)($_POST['contact_id'] ?? 0);
        $channel = ($_POST['channel'] ?? 'email') === 'sms' ? 'sms' : 'email';
        $contact = (new Contact())->find($contactId);
        if (!$contact) {
            flash('error', 'Contact not found.');
            redirect('contacts/index');
        }
        $address = $channel === 'sms' ? (string)($contact['phone'] ?? '') : (string)($contact['email'] ?? '');
        if ($address === '') {
            flash('error', 'This contact does not have a ' . strtoupper($channel) . ' address to restore.');
            $this->redirectToContact($contactId, trim((string)($_POST['comm_tab'] ?? '')) ?: null);
        }
        (new Contact())->setUnsubscribed($channel, $address, false);
        (new Suppression())->removeByAddress($channel, $address);
        (new ConsentLog())->create([
            'contact_id' => $contactId,
            'channel' => $channel,
            'status' => 'opt_in',
            'source' => 'manual',
            'proof_note' => trim((string)($_POST['reason'] ?? 'Manual resubscribe from contact profile')),
            'ip_address' => $_SERVER['REMOTE_ADDR'] ?? null,
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? null,
            'created_by' => current_user()['id'] ?? null,
        ]);
        audit_log('contact.resubscribed', 'contact', $contactId, ['channel' => $channel, 'address' => $address]);
        flash('success', strtoupper($channel) . ' restored for this contact.');
        $this->redirectToContact($contactId, trim((string)($_POST['comm_tab'] ?? '')) ?: null);
    }

    public function updateProfile(): void
    {
        require_permission('contacts.manage');
        verify_csrf();
        $contactId = (int)($_POST['contact_id'] ?? 0);
        if ($contactId > 0) {
            (new Contact())->updateLifecycleProfile($contactId, [
                'lifecycle_stage' => $_POST['lifecycle_stage'] ?? 'lead',
                'score' => (int)($_POST['score'] ?? 0),
                'owner_user_id' => (int)($_POST['owner_user_id'] ?? 0) ?: null,
                'account_id' => (int)($_POST['account_id'] ?? 0) ?: null,
                'pipeline_id' => (int)($_POST['pipeline_id'] ?? 0) ?: null,
            ]);
            audit_log('contact.profile.updated', 'contact', $contactId, [
                'lifecycle_stage' => $_POST['lifecycle_stage'] ?? 'lead',
                'score' => (int)($_POST['score'] ?? 0),
                'account_id' => (int)($_POST['account_id'] ?? 0),
                'pipeline_id' => (int)($_POST['pipeline_id'] ?? 0),
            ]);
            flash('success', 'Contact lifecycle profile updated.');
        }
        $this->redirectToContact($contactId, trim((string)($_POST['comm_tab'] ?? '')) ?: null);
    }

    public function addTask(): void
    {
        require_permission('contacts.manage');
        verify_csrf();
        $contactId = (int)($_POST['contact_id'] ?? 0);
        $taskId = (new ContactTask())->create($_POST);
        audit_log('contact.task.created', 'contact_task', $taskId, ['contact_id' => $contactId]);
        flash('success', 'Task added.');
        $this->redirectToContact($contactId, trim((string)($_POST['comm_tab'] ?? '')) ?: null);
    }

    public function completeTask(): void
    {
        require_permission('contacts.manage');
        $taskId = (int)($_GET['task_id'] ?? 0);
        $contactId = (int)($_GET['contact_id'] ?? 0);
        if ($taskId > 0) {
            (new ContactTask())->markDone($taskId);
            audit_log('contact.task.completed', 'contact_task', $taskId, ['contact_id' => $contactId]);
            flash('success', 'Task marked done.');
        }
        $this->redirectToContact($contactId, trim((string)($_GET['comm_tab'] ?? '')) ?: null);
    }

    public function addNote(): void
    {
        require_permission('contacts.manage');
        verify_csrf();
        $contactId = (int)($_POST['contact_id'] ?? 0);
        $noteId = (new ContactNote())->create($_POST);
        audit_log('contact.note.created', 'contact_note', $noteId, ['contact_id' => $contactId]);
        flash('success', 'Note added.');
        $this->redirectToContact($contactId, trim((string)($_POST['comm_tab'] ?? '')) ?: null);
    }

    public function addReminder(): void
    {
        require_permission('contacts.manage');
        verify_csrf();
        $contactId = (int)($_POST['contact_id'] ?? 0);
        $id = (new Reminder())->create($_POST);
        audit_log('contact.reminder.created', 'reminder', $id, ['contact_id' => $contactId]);
        flash('success', 'Reminder added.');
        $this->redirectToContact($contactId, trim((string)($_POST['comm_tab'] ?? '')) ?: null);
    }

    public function completeReminder(): void
    {
        require_permission('contacts.manage');
        $contactId = (int)($_GET['contact_id'] ?? 0);
        $reminderId = (int)($_GET['reminder_id'] ?? 0);
        if ($reminderId) {
            (new Reminder())->markDone($reminderId);
            audit_log('contact.reminder.completed', 'reminder', $reminderId, ['contact_id' => $contactId]);
            flash('success', 'Reminder completed.');
        }
        $this->redirectToContact($contactId, trim((string)($_GET['comm_tab'] ?? '')) ?: null);
    }

    private function redirectToContact(int $contactId, ?string $tab = null): void
    {
        $url = 'index.php?route=contacts/show&id=' . $contactId;
        if ($tab) {
            $url .= '&comm_tab=' . urlencode($tab);
        }
        redirect_url($url);
    }
}
