<?php
use Core\Controller;
use Core\Auth;

/**
 * Settings Module Controller — System & organization settings
 */
class SettingsController extends Controller

{
    public function __construct()
    {
        parent::__construct();
        $this->requireAuth();
    }

    // ─── Organization Settings ───────────────────────────────
    public function orgSettings(): void
    {
        $this->requirePermission('settings', 'view');
        $org = $this->dbQueryOne("SELECT * FROM organizations WHERE id = ?", [Auth::orgId()]);
        $plans = $this->dbQuery("SELECT * FROM plans WHERE is_active = 1");

        $this->render('settings/org_settings', [
            'pageTitle'  => 'Organization Settings',
            'breadcrumb' => [['label' => 'Settings', 'url' => null]],
            'org'        => $org,
            'plans'      => $plans,
            'locales'    => getLocales(),
            'currencies' => getCurrencies(),
            'timezones'  => DateTimeZone::listIdentifiers(),
        ]);
    }

    public function updateOrgSettings(): void
    {
        $this->requirePermission('settings', 'edit');
        if (!$this->validateCsrf()) {
            $this->setFlash('error', 'Invalid security token.');
            $this->redirect(APP_URL . '/settings');
        }

        $orgId = Auth::orgId();
        $data  = [
            'name'        => sanitize($this->getPost('name', '')),
            'industry'    => sanitize($this->getPost('industry', '')),
            'address'     => sanitize($this->getPost('address', '')),
            'phone'       => sanitize($this->getPost('phone', '')),
            'email'       => sanitize($this->getPost('email', '')),
            'locale'      => $this->getPost('locale', DEFAULT_LOCALE),
            'currency'    => $this->getPost('currency', DEFAULT_CURRENCY),
            'timezone'    => $this->getPost('timezone', DEFAULT_TIMEZONE),
            'date_format' => $this->getPost('date_format', 'd/m/Y'),
            'updated_at'  => date('Y-m-d H:i:s'),
        ];

        // Handle logo upload
        if (!empty($_FILES['logo']['name'])) {
            $upload = $this->uploadFile($_FILES['logo'], 'org_logos', ['image/jpeg', 'image/png', 'image/svg+xml', 'image/webp']);
            if ($upload) {
                $data['logo'] = $upload['path'];
            }
        }

        $this->dbExecute(
            "UPDATE organizations SET " . implode(', ', array_map(fn($k) => "{$k} = ?", array_keys($data))) . " WHERE id = ?",
            [...array_values($data), $orgId]
        );

        logAudit('update_org_settings', 'settings', 'organization', $orgId);
        $this->setFlash('success', 'Organization settings updated successfully.');
        $this->redirect(APP_URL . '/settings');
    }

    // ─── Security Settings ───────────────────────────────────
    public function securitySettings(): void
    {
        $this->requireAuth();
        $user      = Auth::user();
        $otpSecret = $this->dbQueryOne("SELECT * FROM user_otp_secrets WHERE user_id = ?", [$user['id']]);

        $this->render('settings/security', [
            'pageTitle'  => 'Security Settings',
            'breadcrumb' => [['label' => 'Settings', 'url' => APP_URL . '/settings'], ['label' => 'Security', 'url' => null]],
            'otpSecret'  => $otpSecret,
            'sessions'   => $this->dbQuery("SELECT * FROM sessions WHERE user_id = ? ORDER BY created_at DESC LIMIT 10", [$user['id']]),
        ]);
    }

    public function disableOtp(): void
    {
        $this->requireAuth();
        if (!$this->validateCsrf()) {
            $this->setFlash('error', 'Invalid token.');
            $this->redirect(APP_URL . '/settings/security');
        }

        // Require password confirmation before disabling OTP
        $password = $this->getPost('confirm_password', '');
        $user     = $this->dbQueryOne("SELECT * FROM users WHERE id = ?", [Auth::id()]);

        if (!password_verify($password, $user['password'])) {
            $this->setFlash('error', 'Incorrect password. OTP not disabled.');
            $this->redirect(APP_URL . '/settings/security');
        }

        $this->dbExecute("UPDATE user_otp_secrets SET is_enabled = 0 WHERE user_id = ?", [Auth::id()]);
        logAudit('otp_disabled', 'settings', 'user', Auth::id());
        $this->setFlash('success', 'Two-factor authentication has been disabled.');
        $this->redirect(APP_URL . '/settings/security');
    }

    public function revokeSession(string $token): void
    {
        $this->requireAuth();
        $this->dbExecute("DELETE FROM sessions WHERE token = ? AND user_id = ?", [$token, Auth::id()]);
        $this->setFlash('success', 'Session revoked.');
        $this->redirect(APP_URL . '/settings/security');
    }

    // ─── Email / SMTP Settings ───────────────────────────────
    public function emailSettings(): void
    {
        $this->requireSuperAdmin();
        $settings = $this->getSystemSettings(['smtp_host', 'smtp_port', 'smtp_username', 'smtp_from_email', 'smtp_from_name']);
        $this->render('settings/email', [
            'pageTitle'  => 'Email Settings',
            'breadcrumb' => [['label' => 'Settings', 'url' => APP_URL . '/settings'], ['label' => 'Email', 'url' => null]],
            'settings'   => $settings,
        ]);
    }

    public function updateEmailSettings(): void
    {
        $this->requireSuperAdmin();
        if (!$this->validateCsrf()) {
            $this->redirect(APP_URL . '/settings/email');
        }

        $keys = ['smtp_host', 'smtp_port', 'smtp_username', 'smtp_password', 'smtp_from_email', 'smtp_from_name', 'smtp_encryption'];
        foreach ($keys as $key) {
            $value = $this->getPost($key, '');
            if ($key === 'smtp_password' && empty($value)) continue; // Don't clear password if not provided
            $this->upsertSystemSetting($key, $value);
        }

        $this->setFlash('success', 'Email settings updated.');
        $this->redirect(APP_URL . '/settings/email');
    }

    public function testEmail(): void
    {
        $this->requireSuperAdmin();
        if (!$this->validateCsrf()) {
            $this->json(['success' => false, 'message' => 'Invalid security token']);
        }
        $testEmail = $this->getPost('test_email', '');
        if (!filter_var($testEmail, FILTER_VALIDATE_EMAIL)) {
            $this->json(['success' => false, 'message' => 'Invalid email address']);
        }

        $result = sendEmail($testEmail, 'Test User', 'Helmyx Test Email', '
            <h2>Test Email</h2>
            <p>This is a test email from Helmyx. If you received this, your email settings are configured correctly.</p>
        ');

        $this->json(['success' => $result, 'message' => $result ? 'Test email sent successfully!' : 'Failed to send test email. Check SMTP settings.']);
    }

    // ─── Billing / Subscription Settings ─────────────────────
    public function billingSettings(): void
    {
        $this->requireAuth();
        $isSuperAdmin = Auth::isSuperAdmin();
        $orgId  = Auth::orgId();
        $org    = $orgId ? $this->dbQueryOne("SELECT o.*, p.name as plan_name FROM organizations o LEFT JOIN plans p ON o.plan_id = p.id WHERE o.id = ?", [$orgId]) : null;

        $orgFilter = $isSuperAdmin ? '' : 'WHERE sc.org_id = ?';
        $params = $isSuperAdmin ? [] : [$orgId];
        $charges = $this->dbQuery(
            "SELECT sc.*, p.name as project_name, c.company_name as contractor_name, o.name as org_name
             FROM subscription_charges sc
             LEFT JOIN projects p ON sc.project_id = p.id
             LEFT JOIN contractors c ON sc.contractor_id = c.id
             LEFT JOIN organizations o ON sc.org_id = o.id
             {$orgFilter}
             ORDER BY sc.created_at DESC
             LIMIT 50",
            $params
        );

        $statsFilter = $isSuperAdmin ? '' : 'WHERE org_id = ?';
        $stats = $this->dbQueryOne(
            "SELECT SUM(charge_amount) as total_charges,
                    SUM(CASE WHEN status='paid' THEN charge_amount ELSE 0 END) as total_paid,
                    SUM(CASE WHEN status='pending' THEN charge_amount ELSE 0 END) as total_pending,
                    COUNT(*) as total_count
             FROM subscription_charges {$statsFilter}",
            $params
        );

        $this->render('settings/billing', [
            'pageTitle'  => 'Billing & Subscription',
            'breadcrumb' => [['label' => 'Settings', 'url' => APP_URL . '/settings'], ['label' => 'Billing', 'url' => null]],
            'org'        => $org,
            'charges'    => $charges,
            'stats'      => $stats,
        ]);
    }

    // ─── System Settings (Super-Admin) ───────────────────────
    public function systemSettings(): void
    {
        $this->requireSuperAdmin();
        $this->render('settings/system', [
            'pageTitle'  => 'System Settings',
            'breadcrumb' => [['label' => 'Admin', 'url' => null], ['label' => 'System Settings', 'url' => null]],
            'settings'   => $this->getAllSystemSettings(),
            'plans'      => $this->dbQuery("SELECT * FROM plans ORDER BY price ASC"),
        ]);
    }

    public function updateSystemSettings(): void
    {
        $this->requireSuperAdmin();
        if (!$this->validateCsrf()) {
            $this->redirect(APP_URL . '/admin/system');
        }

        $textKeys = ['app_name', 'platform_fee_rate', 'default_locale', 'default_currency', 'default_timezone'];
        foreach ($textKeys as $key) {
            $value = $this->getPost($key, null);
            if ($value !== null) {
                $this->upsertSystemSetting($key, $value);
            }
        }

        // Credential fields — leaving one blank re-saves the existing value rather
        // than wiping it, same as the SMTP password field above.
        $secretKeys = ['flw_public_key', 'flw_secret_key', 'flw_webhook_hash', 'ipinfo_token'];
        foreach ($secretKeys as $key) {
            $value = $this->getPost($key, '');
            if ($value !== '') {
                $this->upsertSystemSetting($key, $value);
            }
        }

        $checkboxKeys = ['maintenance_mode', 'registration_open'];
        foreach ($checkboxKeys as $key) {
            $this->upsertSystemSetting($key, $this->getPost($key) ? '1' : '0');
        }

        $this->setFlash('success', 'System settings updated.');
        $this->redirect(APP_URL . '/admin/system');
    }

    // ─── Plans Management ────────────────────────────────────
    public function plans(): void
    {
        $this->requireSuperAdmin();
        $plans = $this->dbQuery("SELECT p.*, COUNT(o.id) as org_count FROM plans p LEFT JOIN organizations o ON p.id = o.plan_id GROUP BY p.id ORDER BY p.price ASC");

        $pricesByPlan = [];
        foreach ($this->dbQuery("SELECT * FROM plan_currency_prices ORDER BY currency_code ASC") as $row) {
            $pricesByPlan[(int)$row['plan_id']][] = $row;
        }

        $this->render('settings/plans', [
            'pageTitle'    => 'Subscription Plans',
            'plans'        => $plans,
            'pricesByPlan' => $pricesByPlan,
            'currencies'   => getCurrencies(),
        ]);
    }

    /**
     * Replace a plan's per-currency price list. Used by the trial-expiry
     * payment flow (Core\Pricing) to charge the amount the admin set for
     * whichever currency the visitor's IP resolves to.
     */
    public function savePlanPrices($id): void
    {
        $this->requireSuperAdmin();
        if (!$this->validateCsrf()) {
            $this->setFlash('error', 'Invalid security token.');
            $this->redirect(APP_URL . '/admin/plans');
        }

        $planId = (int)$id;
        if (!$this->dbQueryOne("SELECT id FROM plans WHERE id = ?", [$planId])) {
            $this->setFlash('error', 'Plan not found.');
            $this->redirect(APP_URL . '/admin/plans');
        }

        $codes   = $this->getPost('currency', []);
        $amounts = $this->getPost('amount', []);

        $this->dbExecute("DELETE FROM plan_currency_prices WHERE plan_id = ?", [$planId]);

        if (is_array($codes)) {
            foreach ($codes as $i => $code) {
                $code   = strtoupper(trim((string)$code));
                $amount = (float)($amounts[$i] ?? 0);
                if ($code === '' || $amount <= 0) continue;
                $this->dbExecute(
                    "INSERT INTO plan_currency_prices (plan_id, currency_code, amount, created_at, updated_at)
                     VALUES (?, ?, ?, NOW(), NOW())
                     ON DUPLICATE KEY UPDATE amount = VALUES(amount), updated_at = NOW()",
                    [$planId, $code, $amount]
                );
            }
        }

        $this->setFlash('success', 'Currency pricing updated.');
        $this->redirect(APP_URL . '/admin/plans');
    }

    public function savePlan(): void
    {
        $this->requireSuperAdmin();
        if (!$this->validateCsrf()) {
            $this->redirect(APP_URL . '/admin/plans');
        }

        $id   = (int) $this->getPost('id', 0);
        $data = [
            'name'         => sanitize($this->getPost('name', '')),
            'description'  => sanitize($this->getPost('description', '')),
            'price'        => (float) $this->getPost('price', 0),
            'billing_type' => $this->getPost('billing_type', 'monthly'),
            'features'     => json_encode(array_filter(explode("\n", $this->getPost('features', '')))),
            'is_active'    => (int) (bool) $this->getPost('is_active', 0),
        ];

        if ($id) {
            $data['updated_at'] = date('Y-m-d H:i:s');
            $this->dbExecute(
                "UPDATE plans SET " . implode(', ', array_map(fn($k) => "{$k} = ?", array_keys($data))) . " WHERE id = ?",
                [...array_values($data), $id]
            );
        } else {
            $data['created_at'] = $data['updated_at'] = date('Y-m-d H:i:s');
            $this->dbExecute(
                "INSERT INTO plans (" . implode(', ', array_keys($data)) . ") VALUES (" . implode(', ', array_fill(0, count($data), '?')) . ")",
                array_values($data)
            );
        }

        $this->setFlash('success', 'Plan saved successfully.');
        $this->redirect(APP_URL . '/admin/plans');
    }

    // ─── Audit Log ───────────────────────────────────────────
    public function auditLog(): void
    {
        $this->requirePermission('settings', 'view');
        $page = max(1, (int) ($this->getGet('page', 1)));
        $orgId = Auth::isSuperAdmin() ? null : Auth::orgId();

        $where  = $orgId ? "WHERE al.org_id = {$orgId}" : '';
        $total  = $this->dbQueryOne("SELECT COUNT(*) as cnt FROM audit_logs al {$where}")['cnt'] ?? 0;
        $offset = ($page - 1) * 20;

        $logs = $this->dbQuery(
            "SELECT al.*, CONCAT(u.first_name, ' ', u.last_name) as user_name, u.email as user_email
             FROM audit_logs al
             LEFT JOIN users u ON al.user_id = u.id
             {$where}
             ORDER BY al.created_at DESC
             LIMIT 20 OFFSET {$offset}"
        );

        $this->render('settings/audit_log', [
            'pageTitle'      => 'Audit Log',
            'breadcrumb'     => [['label' => 'Settings', 'url' => APP_URL . '/settings'], ['label' => 'Audit Log', 'url' => null]],
            'logs'           => $logs,
            'paginationData' => [
                'current_page' => $page,
                'total_pages'  => (int)ceil($total / 20),
                'total_items'  => (int)$total,
                'url_pattern'  => APP_URL . '/settings/audit?page=',
            ],
        ]);
    }

    // ─── Private Helpers ─────────────────────────────────────

    private function getSystemSettings(array $keys): array
    {
        $settings = [];
        $rows = $this->dbQuery(
            "SELECT setting_key, setting_value FROM organization_settings WHERE org_id IS NULL AND setting_key IN (" . implode(',', array_fill(0, count($keys), '?')) . ")",
            $keys
        );
        foreach ($rows as $row) {
            $settings[$row['setting_key']] = $row['setting_value'];
        }
        return $settings;
    }

    private function getAllSystemSettings(): array
    {
        $rows = $this->dbQuery("SELECT setting_key, setting_value FROM organization_settings WHERE org_id IS NULL");
        $settings = [];
        foreach ($rows as $row) {
            $settings[$row['setting_key']] = $row['setting_value'];
        }
        return $settings;
    }

    private function upsertSystemSetting(string $key, string $value): void
    {
        $existing = $this->dbQueryOne("SELECT id FROM organization_settings WHERE org_id IS NULL AND setting_key = ?", [$key]);
        if ($existing) {
            $this->dbExecute("UPDATE organization_settings SET setting_value = ? WHERE org_id IS NULL AND setting_key = ?", [$value, $key]);
        } else {
            $this->dbExecute("INSERT INTO organization_settings (org_id, setting_key, setting_value, created_at, updated_at) VALUES (NULL, ?, ?, NOW(), NOW())", [$key, $value]);
        }
    }
}
