<?php
require_once __DIR__ . '/../Core.php';
require_once __DIR__ . '/../models/Setting.php';
require_once __DIR__ . '/../models/User.php';
require_once __DIR__ . '/../models/Contact.php';
require_once __DIR__ . '/../models/UserPermission.php';
require_once __DIR__ . '/../models/Suppression.php';
require_once __DIR__ . '/../models/UserIntegrationProfile.php';
require_once __DIR__ . '/../models/CustomField.php';
require_once __DIR__ . '/../models/AuditLog.php';
require_once __DIR__ . '/../models/QueueJob.php';
require_once __DIR__ . '/../models/Message.php';
require_once __DIR__ . '/../models/Workflow.php';
require_once __DIR__ . '/../models/Template.php';
require_once __DIR__ . '/../models/Segment.php';
require_once __DIR__ . '/../models/CannedReply.php';
require_once __DIR__ . '/../models/Account.php';
require_once __DIR__ . '/../models/Pipeline.php';
require_once __DIR__ . '/../models/Reminder.php';
require_once __DIR__ . '/../models/LoginHistory.php';
require_once __DIR__ . '/../services.php';

class SettingsController extends Controller
{
    public function index(): void
    {
        require_permission('settings.view');
        $permissionModel = new UserPermission();
        $users = (new User())->all();
        foreach ($users as &$user) {
            $user['permission_overrides'] = $permissionModel->mapForUser((int)$user['id']);
        }
        $this->view('settings/index', [
            'settings' => (new Setting())->all(),
            'users' => $users,
            'allPermissions' => all_permissions(),
            'suppressions' => (new Suppression())->all(),
            'customFields' => (new CustomField())->all(),
            'appVersion' => app_version(),
            'schemaVersion' => schema_version(),
            'schemaMatches' => schema_matches_app_version(),
            'appVersionSource' => app_version_source(),
            'workflows' => (new Workflow())->all(),
            'workflowStats' => (new Workflow())->stats(),
            'templates' => (new Template())->all(),
            'segments' => (new Segment())->all(),
            'cannedReplies' => (new CannedReply())->all(),
            'accounts' => (new Account())->all(),
            'pipelines' => (new Pipeline())->all(),
            'reminders' => (new Reminder())->upcoming(20),
            'providerStatus' => provider_status_summary(),
            'quietHours' => quiet_hours_settings(),
        ]);
    }

    public function diagnostics(): void
    {
        require_permission('settings.view');
        $queue = new QueueJob();
        $this->view('settings/diagnostics', [
            'appVersion' => app_version(),
            'schemaVersion' => schema_version(),
            'schemaMatches' => schema_matches_app_version(),
            'appVersionSource' => app_version_source(),
            'heartbeat' => worker_heartbeat(),
            'queueStats' => $queue->stats(),
            'queueJobs' => $queue->recent(25),
            'deadLetters' => $queue->deadLetters(25),
            'auditLogs' => (new AuditLog())->recent(30),
            'recentMessages' => (new Message())->recent(20),
            'failedQueueJobs' => $queue->failed(25),
            'loginHistory' => (new LoginHistory())->recent(25),
            'missingTables' => app_missing_tables(Database::connection()),
        ]);
    }

    public function retryQueueJob(): void
    {
        require_permission('settings.manage');
        $id = (int)($_GET['id'] ?? 0);
        if ($id <= 0) {
            flash('error', 'Queue job not found.');
            redirect('settings/diagnostics');
        }
        (new QueueJob())->retryFailed($id);
        audit_log('queue.job.retried', 'queue_job', $id);
        flash('success', 'Failed queue job requeued.');
        redirect('settings/diagnostics');
    }

    public function replayDeadLetter(): void
    {
        require_permission('settings.manage');
        $id = (int)($_GET['id'] ?? 0);
        if ($id <= 0) {
            flash('error', 'Dead-letter item not found.');
            redirect('settings/diagnostics');
        }
        $newJobId = (new QueueJob())->requeueDeadLetter($id);
        if ($newJobId) {
            audit_log('queue.dead_letter.replayed', 'queue_dead_letter', $id, ['new_queue_job_id' => $newJobId]);
            flash('success', 'Dead-letter job requeued as job #' . $newJobId . '.');
        } else {
            flash('error', 'Dead-letter item could not be requeued.');
        }
        redirect('settings/diagnostics');
    }

    public function syncSchemaVersion(): void
    {
        require_permission('settings.manage');
        verify_csrf();
        (new Setting())->set('schema_version', app_version());
        audit_log('schema.version.synced', 'settings', null, [
            'app_version' => app_version(),
            'previous_schema_version' => schema_version(),
            'source' => app_version_source(),
        ]);
        flash('success', 'Schema version synchronized to app version ' . app_version() . '.');
        redirect('settings/diagnostics');
    }

    public function providerStatus(): void
    {
        require_permission('settings.view');
        $settingModel = new Setting();
        $storedResults = json_decode((string)$settingModel->get('provider_last_test_results_json', '[]'), true) ?: [];
        $this->view('settings/provider_status', [
            'providerStatus' => provider_status_summary(),
            'providerDetails' => [
                'twilio' => effective_twilio_config(),
                'smtp' => effective_mail_config(),
                'sendgrid' => [
                    'endpoint' => effective_mail_config()['sendgrid_api_base_url'] ?? 'https://api.sendgrid.com',
                    'webhook_url' => sendgrid_webhook_url(),
                    'webhook_token' => effective_mail_config()['sendgrid_webhook_token'] ?? '',
                ],
                'imap' => [
                    'host' => (string)setting_value('imap_host', config('imap.host')),
                    'port' => (int)setting_value('imap_port', config('imap.port', 993)),
                    'flags' => (string)setting_value('imap_flags', config('imap.flags', '/imap/ssl')),
                    'mailbox' => (string)setting_value('imap_mailbox', config('imap.mailbox', 'INBOX')),
                    'username' => (string)setting_value('imap_username', config('imap.username')),
                ],
            ],
            'testResults' => flash('provider_test_results') ?: $storedResults,
            'lastTestedAt' => $settingModel->get('provider_last_tested_at', null),
        ]);
    }

    public function runProviderTests(): void
    {
        require_permission('settings.view');
        verify_csrf();
        $results = [
            'twilio' => ['ok' => false, 'message' => 'Not configured'],
            'sendgrid' => ['ok' => null, 'message' => 'Not selected'],
            'smtp' => ['ok' => null, 'message' => 'Not selected'],
            'imap' => ['ok' => false, 'message' => 'Not configured'],
        ];

        $twilio = effective_twilio_config();
        if (!empty($twilio['sid']) && !empty($twilio['token'])) {
            $started = microtime(true);
            $ch = curl_init('https://api.twilio.com/2010-04-01/Accounts/' . $twilio['sid'] . '.json');
            curl_setopt_array($ch, [
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_TIMEOUT => 15,
                CURLOPT_USERPWD => $twilio['sid'] . ':' . $twilio['token'],
                CURLOPT_HTTPHEADER => ['Accept: application/json'],
            ]);
            $body = curl_exec($ch);
            $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
            $error = curl_error($ch);
            curl_close($ch);
            $latency = (int)round((microtime(true) - $started) * 1000);
            $decoded = json_decode((string)$body, true) ?: [];
            if ($error) {
                $results['twilio'] = ['ok' => false, 'message' => $error, 'latency_ms' => $latency];
            } else {
                $results['twilio'] = [
                    'ok' => ($code >= 200 && $code < 300),
                    'message' => 'HTTP ' . $code . (!empty($decoded['friendly_name']) ? ' • ' . $decoded['friendly_name'] : ''),
                    'latency_ms' => $latency,
                    'account_status' => $decoded['status'] ?? null,
                ];
            }
        }
        $mail = effective_mail_config();
        $mailService = new EmailService();
        $mailTransport = mail_delivery_transport($mail);
        if ($mailTransport === 'sendgrid_api') {
            $results['sendgrid'] = $mailService->testMailConnection($mail);
            $results['smtp'] = ['ok' => null, 'message' => 'SMTP not selected'];
        } elseif ($mailTransport === 'smtp' && !empty($mail['smtp_host']) && !empty($mail['smtp_port'])) {
            $results['smtp'] = $mailService->testMailConnection($mail);
            if (!empty($mail['sendgrid_api_key'])) {
                $results['sendgrid'] = ['ok' => null, 'message' => 'Configured but not selected'];
            }
        } elseif ($mailTransport === 'php_mail') {
            $results['smtp'] = ['ok' => null, 'message' => 'PHP mail() selected; no live handshake available'];
            if (!empty($mail['sendgrid_api_key'])) {
                $results['sendgrid'] = ['ok' => null, 'message' => 'Configured but not selected'];
            }
        }

        $imapHost = (string)setting_value('imap_host', config('imap.host'));
        if ($imapHost !== '' && function_exists('imap_open')) {
            $started = microtime(true);
            $mailbox = sprintf('{%s:%d%s}%s', $imapHost, (int)setting_value('imap_port', config('imap.port', 993)), (string)setting_value('imap_flags', config('imap.flags', '/imap/ssl')), (string)setting_value('imap_mailbox', config('imap.mailbox', 'INBOX')));
            $imap = @imap_open($mailbox, (string)setting_value('imap_username', config('imap.username')), (string)setting_value('imap_password', config('imap.password')));
            if ($imap) {
                $count = (int)imap_num_msg($imap);
                $sample = null;
                if ($count > 0) {
                    $overview = imap_fetch_overview($imap, (string)$count, 0)[0] ?? null;
                    if ($overview) {
                        $sample = trim((string)($overview->subject ?? ''));
                    }
                }
                imap_close($imap);
                $latency = (int)round((microtime(true) - $started) * 1000);
                $results['imap'] = ['ok' => true, 'message' => 'Connected • ' . $count . ' messages visible' . ($sample ? ' • Latest: ' . $sample : ''), 'latency_ms' => $latency];
            } else {
                $results['imap'] = ['ok' => false, 'message' => imap_last_error() ?: 'Unable to connect'];
            }
        } elseif ($imapHost !== '') {
            $results['imap'] = ['ok' => false, 'message' => 'PHP IMAP extension is not installed'];
        }

        $settingModel = new Setting();
        $settingModel->set('provider_last_test_results_json', json_encode($results));
        $settingModel->set('provider_last_tested_at', date('Y-m-d H:i:s'));
        flash('provider_test_results', $results);
        redirect('settings/providerStatus');
    }

    public function profile(): void
    {
        $user = current_user();
        if (!$user) {
            redirect('auth/login');
        }
        $freshUser = (new User())->find((int)$user['id']) ?: $user;
        $secret = generate_totp_secret();
        start_session();
        $_SESSION['pending_profile_2fa_secret'] = $secret;
        $this->view('settings/profile', [
            'profile' => (new UserIntegrationProfile())->findByUserId((int)$user['id']) ?: [],
            'user' => $freshUser,
            'pendingTwoFactorSecret' => $secret,
            'pendingTwoFactorUri' => otp_auth_uri($freshUser['email'], $secret),
        ]);
    }

    public function save(): void
    {
        require_permission('settings.manage');
        verify_csrf();
        $model = new Setting();
        foreach ($_POST as $key => $value) {
            if ($key === '_csrf') {
                continue;
            }
            $model->set($key, is_array($value) ? json_encode($value) : (string)$value);
        }
        flash('success', 'Settings saved.');
        redirect('settings/index');
    }

    public function saveIntegrations(): void
    {
        require_permission('settings.manage');
        verify_csrf();
        $model = new Setting();
        $fields = [
            'twilio_sid','twilio_token','twilio_from_number','twilio_validate_signature',
            'mail_from_name','mail_from_email','mail_transport','mail_smtp_enabled','mail_smtp_host','mail_smtp_port','mail_smtp_username','mail_smtp_password','mail_smtp_secure',
            'mail_sendgrid_api_key','mail_sendgrid_api_base_url','mail_sendgrid_webhook_token',
            'imap_host','imap_port','imap_flags','imap_username','imap_password','imap_mailbox',
            'reply_to_email','default_sms_footer','default_email_footer','preferred_channel'
        ];
        $_POST['mail_smtp_enabled'] = ($_POST['mail_transport'] ?? '') === 'smtp' ? '1' : '0';
        foreach ($fields as $field) {
            $model->set($field, (string)($_POST[$field] ?? ''));
        }
        audit_log('integrations.updated', 'settings', null, ['scope' => 'global']);
        flash('success', 'Integration settings updated.');
        redirect('settings/index');
    }

    public function saveMyProfile(): void
    {
        verify_csrf();
        $user = current_user();
        if (!$user) {
            redirect('auth/login');
        }
        (new UserIntegrationProfile())->saveForUser((int)$user['id'], $_POST);
        audit_log('integrations.updated', 'user', (int)$user['id'], ['scope' => 'personal']);
        flash('success', 'Your sending profile was saved.');
        redirect('settings/profile');
    }

    public function enableTwoFactor(): void
    {
        verify_csrf();
        $user = current_user();
        if (!$user) { redirect('auth/login'); }
        start_session();
        $secret = (string)($_SESSION['pending_profile_2fa_secret'] ?? '');
        $code = trim($_POST['code'] ?? '');
        if ($secret === '' || !verify_totp_code($secret, $code)) {
            flash('error', 'Invalid two-factor code.');
            redirect('settings/profile');
        }
        (new User())->enableTwoFactor((int)$user['id'], $secret);
        unset($_SESSION['pending_profile_2fa_secret']);
        audit_log('user.2fa.enabled', 'user', (int)$user['id']);
        flash('success', 'Two-factor authentication enabled.');
        redirect('settings/profile');
    }

    public function disableTwoFactor(): void
    {
        verify_csrf();
        $user = current_user();
        if (!$user) { redirect('auth/login'); }
        (new User())->disableTwoFactor((int)$user['id']);
        audit_log('user.2fa.disabled', 'user', (int)$user['id']);
        flash('success', 'Two-factor authentication disabled.');
        redirect('settings/profile');
    }

    public function saveCustomField(): void
    {
        require_permission('contacts.manage');
        verify_csrf();
        $key = preg_replace('/[^a-z0-9_]+/i', '_', strtolower(trim($_POST['field_key'] ?? '')));
        if ($key === '') {
            flash('error', 'Field key is required.');
            redirect('settings/index');
        }
        $id = (new CustomField())->create([
            'name' => $_POST['name'] ?? 'Field',
            'field_key' => $key,
            'field_type' => $_POST['field_type'] ?? 'text',
            'sort_order' => (int)($_POST['sort_order'] ?? 0),
        ]);
        audit_log('custom_field.created', 'custom_field', $id, ['field_key' => $key]);
        flash('success', 'Custom field added.');
        redirect('settings/index');
    }

    public function deleteCustomField(): void
    {
        require_permission('contacts.manage');
        $id = (int)($_GET['id'] ?? 0);
        if ($id) {
            (new CustomField())->delete($id);
            audit_log('custom_field.deleted', 'custom_field', $id);
            flash('success', 'Custom field removed.');
        }
        redirect('settings/index');
    }

    public function createUser(): void
    {
        require_permission('users.manage');
        verify_csrf();
        try {
            (new User())->create($_POST);
            flash('success', 'User created successfully.');
        } catch (Throwable $e) {
            flash('error', $e->getMessage());
        }
        redirect('settings/index');
    }

    public function savePermissions(): void
    {
        require_permission('users.manage');
        verify_csrf();
        $userId = (int)($_POST['user_id'] ?? 0);
        if (!$userId) {
            flash('error', 'User is required.');
            redirect('settings/index');
        }
        (new UserPermission())->replaceForUser($userId, $_POST['permissions'] ?? []);
        audit_log('user.permissions.updated', 'user', $userId, ['permissions' => $_POST['permissions'] ?? []]);
        flash('success', 'User permissions updated.');
        redirect('settings/index');
    }

    public function addSuppression(): void
    {
        require_permission('settings.manage');
        verify_csrf();
        try {
            $channel = $_POST['channel'] ?? 'email';
            $address = trim($_POST['address'] ?? '');
            $reason = trim($_POST['reason'] ?? 'manual');
            (new Suppression())->add($channel, $address, $reason ?: 'manual', null, null);
            if ($channel === 'sms' || $channel === 'email') {
                (new Contact())->setUnsubscribed($channel, $address, true);
            }
            audit_log('suppression.added', 'suppression', null, ['channel' => $channel, 'address' => $address, 'reason' => $reason]);
            flash('success', 'Suppression added.');
        } catch (Throwable $e) {
            flash('error', $e->getMessage());
        }
        redirect('settings/index');
    }

    public function deleteSuppression(): void
    {
        require_permission('settings.manage');
        $id = (int)($_GET['id'] ?? 0);
        if ($id) {
            (new Suppression())->delete($id);
            audit_log('suppression.deleted', 'suppression', $id);
            flash('success', 'Suppression removed.');
        }
        redirect('settings/index');
    }

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

    public function toggleWorkflow(): void
    {
        require_permission('settings.manage');
        $id = (int)($_GET['id'] ?? 0);
        if ($id) {
            (new Workflow())->toggle($id);
            audit_log('workflow.toggled', 'workflow', $id);
            flash('success', 'Workflow updated.');
        }
        redirect('settings/index');
    }

    public function saveCannedReply(): void
    {
        require_permission('messages.reply');
        verify_csrf();
        $id = (new CannedReply())->create($_POST);
        audit_log('canned_reply.created', 'canned_reply', $id, ['title' => $_POST['title'] ?? null]);
        flash('success', 'Canned reply saved.');
        redirect('settings/index');
    }

    public function deleteCannedReply(): void
    {
        require_permission('messages.reply');
        $id = (int)($_GET['id'] ?? 0);
        if ($id) {
            (new CannedReply())->delete($id);
            audit_log('canned_reply.deleted', 'canned_reply', $id);
            flash('success', 'Canned reply removed.');
        }
        redirect('settings/index');
    }

    public function saveComplianceSettings(): void
    {
        require_permission('settings.manage');
        verify_csrf();
        $model = new Setting();
        foreach (['quiet_hours_enabled','quiet_hours_start','quiet_hours_end','quiet_hours_timezone','suppression_automation_enabled'] as $field) {
            $model->set($field, (string)($_POST[$field] ?? ''));
        }
        audit_log('compliance.settings.updated', 'settings');
        flash('success', 'Compliance settings saved.');
        redirect('settings/index');
    }

    public function exportAuditCsv(): void
    {
        require_permission('settings.view');
        $rows = (new AuditLog())->recent(500);
        header('Content-Type: text/csv');
        header('Content-Disposition: attachment; filename="audit_export.csv"');
        $out = fopen('php://output', 'w');
        fputcsv($out, ['When','Action','Entity Type','Entity ID','User ID','Details']);
        foreach ($rows as $row) {
            fputcsv($out, [$row['created_at'], $row['action'], $row['entity_type'], $row['entity_id'], $row['user_id'], $row['details_json']]);
        }
        fclose($out);
        exit;
    }

    public function createAccount(): void
    {
        require_permission('contacts.manage');
        verify_csrf();
        $id = (new Account())->create($_POST);
        audit_log('account.created', 'account', $id);
        flash('success', 'Account created.');
        redirect('settings/index');
    }

    public function createPipeline(): void
    {
        require_permission('contacts.manage');
        verify_csrf();
        $id = (new Pipeline())->create($_POST);
        audit_log('pipeline.created', 'pipeline', $id);
        flash('success', 'Pipeline created.');
        redirect('settings/index');
    }
}
