<?php

namespace Modules\Settings\Controllers;

use core\Controller;
use core\Auth;
use core\Database;
use core\Security;
use core\Session;

class SettingController extends Controller
{
    public function __construct()
    {
        parent::__construct();
    }

    public function index(): void
    {
        $this->requirePermission('settings_view');

        $db = Database::getInstance();
        $settings = [];
        $rows = $db->table('settings')->get();
        foreach ($rows as $row) {
            $settings[$row->key] = $row->value;
        }

        $this->view('Settings/index', [
            'title' => 'Settings',
            'breadcrumb' => ['Settings' => url('settings')],
            'settings' => $settings,
        ]);
    }

    public function update(): void
    {
        $this->requirePermission('settings_update');

        try {
            $db = Database::getInstance();
            $data = $_POST;

            foreach ($data as $key => $value) {
                if (str_starts_with($key, '_')) {
                    continue;
                }
                if (is_array($value)) {
                    $value = implode(',', $value);
                }
                $existing = $db->table('settings')->where('key', $key)->first();
                if ($existing) {
                    $db->table('settings')->where('key', $key)->update(['value' => $value]);
                } else {
                    $db->table('settings')->insert(['key' => $key, 'value' => $value]);
                }
            }

            $cacheFile = PATH_STORAGE . DS . 'cache' . DS . 'settings.cache';
            if (file_exists($cacheFile)) {
                unlink($cacheFile);
            }

            $this->logActivity('update', 'Updated system settings');
            $this->redirectWith(url('settings'), 'success', 'Settings updated successfully.');
        } catch (\Throwable $e) {
            $errorMsg = date('Y-m-d H:i:s') . ' [SETTINGS_UPDATE] ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine() . PHP_EOL;
            file_put_contents(PATH_STORAGE . DS . 'logs' . DS . 'error.log', $errorMsg, FILE_APPEND);
            Session::setAlert('danger', 'Failed to save settings: ' . $e->getMessage());
            $this->redirect(url('settings'));
        }
    }

    public function backup(): void
    {
        $this->requirePermission('settings_backup');

        $db = Database::getInstance();
        $backups = $db->table('backups')
            ->orderBy('created_at', 'DESC')
            ->get();

        $this->view('Settings/backup', [
            'title' => 'Backup Management',
            'breadcrumb' => [
                'Settings' => url('settings'),
                'Backup' => url('settings/backup'),
            ],
            'backups' => $backups,
        ]);
    }

    public function createBackup(): void
    {
        $this->requirePermission('settings_backup');

        $db = Database::getInstance();
        $filename = 'backup_' . date('Ymd_His') . '.sql';
        $filepath = PATH_STORAGE . DS . 'backups' . DS . $filename;

        if (!is_dir(PATH_STORAGE . DS . 'backups')) {
            mkdir(PATH_STORAGE . DS . 'backups', 0755, true);
        }

        $tables = $db->raw('SHOW TABLES');
        $sql = '';

        foreach ($tables as $table) {
            $tableName = array_values((array)$table)[0];
            $createTable = $db->raw('SHOW CREATE TABLE `' . $tableName . '`');
            $sql .= '-- Table: ' . $tableName . "\n";
            $sql .= $createTable[0]->{'Create Table'} . ";\n\n";

            $rows = $db->table($tableName)->get();
            foreach ($rows as $row) {
                $cols = array_keys((array)$row);
                $vals = array_map(function ($v) {
                    return "'" . addslashes($v) . "'";
                }, array_values((array)$row));
                $sql .= "INSERT INTO `{$tableName}` (`" . implode('`, `', $cols) . "`) VALUES (" . implode(', ', $vals) . ");\n";
            }
            $sql .= "\n";
        }

        file_put_contents($filepath, $sql);

        $backupId = $db->table('backups')->insert([
            'filename' => $filename,
            'filepath' => 'backups/' . $filename,
            'size' => filesize($filepath),
            'created_by' => Auth::id(),
            'created_at' => date(DATE_TIME_FORMAT),
        ]);

        $this->logActivity('backup', 'Created database backup: ' . $filename);
        $this->redirectWith(url('settings/backup'), 'success', 'Backup created successfully.');
    }

    public function restoreBackup(int $id): void
    {
        $this->requirePermission('settings_backup');

        $db = Database::getInstance();
        $backup = $db->table('backups')->find($id);
        if (!$backup) {
            $this->redirectWith(url('settings/backup'), 'error', 'Backup not found.');
        }

        $filepath = PATH_STORAGE . DS . $backup->filepath;
        if (!file_exists($filepath)) {
            $this->redirectWith(url('settings/backup'), 'error', 'Backup file not found.');
        }

        $sql = file_get_contents($filepath);
        $statements = explode(";\n", $sql);

        try {
            $db->beginTransaction();
            foreach ($statements as $statement) {
                $statement = trim($statement);
                if (!empty($statement) && stripos($statement, 'INSERT') === 0) {
                    $db->execute($statement);
                }
            }
            $db->commit();
        } catch (\Throwable $e) {
            $db->rollback();
            $this->redirectWith(url('settings/backup'), 'error', 'Restore failed: ' . $e->getMessage());
        }

        $this->logActivity('restore', 'Restored database from backup: ' . $backup->filename);
        $this->redirectWith(url('settings/backup'), 'success', 'Backup restored successfully.');
    }

    public function downloadBackup(int $id): void
    {
        $this->requirePermission('settings_backup');

        $db = Database::getInstance();
        $backup = $db->table('backups')->find($id);
        if (!$backup) {
            $this->redirectWith(url('settings/backup'), 'error', 'Backup not found.');
        }

        $filepath = PATH_STORAGE . DS . $backup->filepath;
        if (!file_exists($filepath)) {
            $this->redirectWith(url('settings/backup'), 'error', 'Backup file not found.');
        }

        header('Content-Type: application/sql');
        header('Content-Disposition: attachment; filename="' . $backup->filename . '"');
        header('Content-Length: ' . filesize($filepath));
        readfile($filepath);
        exit;
    }

    public function clearData(): void
    {
        if (!Auth::isSuperadmin()) {
            Session::setAlert('danger', 'Only superadmins can clear all data.');
            $this->redirect(url('settings/backup'));
            return;
        }

        if (!Security::validateCsrfToken($this->request->post(CSRF_TOKEN_NAME))) {
            Session::setAlert('danger', 'Invalid security token.');
            $this->redirect(url('settings/backup'));
            return;
        }

        $confirm = $this->request->post('confirm');
        if ($confirm !== 'CLEAR') {
            Session::setAlert('danger', 'Please type CLEAR to confirm.');
            $this->redirect(url('settings/backup'));
            return;
        }

        $db = Database::getInstance();

        $transactionalTables = [
            'appointment_services',
            'appointment_reminders',
            'appointments',
            'invoice_coupons',
            'invoice_payments',
            'invoice_items',
            'invoices',
            'refunds',
            'purchase_order_items',
            'purchase_orders',
            'grn_items',
            'goods_received_notes',
            'stock_transfer_items',
            'stock_transfers',
            'stock_adjustments',
            'stock_movements',
            'product_batches',
            'employee_attendance',
            'employee_commissions',
            'employee_salary',
            'employee_performance',
            'expenses',
            'income',
            'cash_book',
            'bank_transactions',
            'petty_cash',
            'campaign_logs',
            'campaigns',
            'notifications',
            'email_queue',
            'customer_memberships',
            'loyalty_points',
            'gift_card_transactions',
        ];

        try {
            $db->raw('SET FOREIGN_KEY_CHECKS = 0');

            foreach ($transactionalTables as $table) {
                $db->raw("TRUNCATE TABLE `{$table}`");
            }

            $db->table('products')->update(['current_stock' => 0]);

            $db->raw('SET FOREIGN_KEY_CHECKS = 1');

            Auth::logActivity('data_clear', 'Cleared all transactional data');
            Session::setAlert('success', 'All transactional data cleared successfully.');
        } catch (\Throwable $e) {
            $db->raw('SET FOREIGN_KEY_CHECKS = 1');
            Session::setAlert('danger', 'Failed to clear data: ' . $e->getMessage());
        }

        $this->redirect(url('settings/backup'));
    }
}
