<?php

namespace App\Controllers;

use App\Controllers\BaseController;
use App\Models\UserModel;
use CodeIgniter\HTTP\ResponseInterface;

class Admin extends BaseController
{
    protected $userModel;
    protected $email;

    public function __construct()
    {
        $this->userModel = new UserModel();
        $this->email = \Config\Services::email();
        // Ensure only superadmins can access admin functions
        if (session()->get('role') !== 'superadmin') {
            throw new \CodeIgniter\Exceptions\PageNotFoundException('Access denied');
        }
    }

    /**
     * Display the list of admins
     *
     * @return string
     */
    public function index()
    {
        $data['admins'] = $this->userModel
            ->where('role', 'admin')
            ->orderBy('created_at', 'DESC')
            ->findAll();

        return view('admin/list', $data);
    }

    /**
     * Show the form to create a new admin
     *
     * @return string
     */
    public function create()
    {
        return view('admin/create');
    }

    /**
     * Process the creation of a new admin
     *
     * @return ResponseInterface
     */
    public function store()
    {
        // Validate input
        $rules = [
            'username' => 'required|min_length[3]|max_length[50]|is_unique[users.username]',
            'email'    => 'required|valid_email|is_unique[users.email]',
            'password' => [
                'rules' => 'required|min_length[12]|regex_match[/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{12,}$/]',
                'errors' => [
                    'required' => 'Password is required',
                    'min_length' => 'Password must be at least 12 characters long',
                    'regex_match' => 'Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character'
                ]
            ],
            'confirm_password' => 'required|matches[password]',
        ];

        if (!$this->validate($rules)) {
            return view('admin/create', [
                'validation' => $this->validator,
            ]);
        }

        // Get input data
        $username = $this->request->getPost('username');
        $email = $this->request->getPost('email');
        $password = $this->request->getPost('password');

        // Store admin data in session temporarily
        $adminData = [
            'username' => $username,
            'email' => $email,
            'password' => $password,
            'role' => 'admin'
        ];
        session()->set('pending_admin', $adminData);

        // Generate 6-digit OTP
        $otp = rand(100000, 999999);

        // Set expiration time (30 minutes from now)
        $expiresAt = date('Y-m-d H:i:s', strtotime('+30 minutes'));

        // Store OTP in session
        session()->set('admin_creation_otp', [
            'otp' => $otp,
            'expires_at' => $expiresAt
        ]);

        // Send OTP via email
        $emailSent = $this->sendOtpEmail($email, $otp, 'creation');

        if (!$emailSent) {
            session()->setFlashdata('error', 'Failed to send OTP email. Please try again.');
            return redirect()->back()->withInput();
        }

        // Redirect to OTP verification page
        return redirect()->to('/admin/verify-otp');
    }

    /**
     * Display the OTP verification form for admin creation
     *
     * @return string
     */
    public function verifyOtp()
    {
        // Check if we have pending admin data in session
        if (!session()->get('pending_admin')) {
            return redirect()->to('/admin/create');
        }

        return view('admin/verify_otp');
    }

    /**
     * Process the OTP verification for admin creation
     *
     * @return ResponseInterface
     */
    public function processOtp()
    {
        // Check if we have pending admin data in session
        if (!session()->get('pending_admin')) {
            return redirect()->to('/admin/create');
        }

        // Validate input
        $rules = [
            'otp' => 'required|exact_length[6]',
        ];

        if (!$this->validate($rules)) {
            return view('admin/verify_otp', [
                'validation' => $this->validator,
            ]);
        }

        // Get input data
        $otp = $this->request->getPost('otp');

        // Get OTP data from session
        $otpData = session()->get('admin_creation_otp');

        if (!$otpData) {
            session()->setFlashdata('error', 'OTP session expired. Please try again.');
            return redirect()->to('/admin/create');
        }

        // Check if OTP matches and is not expired
        if ($otpData['otp'] != $otp) {
            session()->setFlashdata('error', 'Invalid OTP. Please try again.');
            return redirect()->back()->withInput();
        }

        // Check if OTP is expired
        if (strtotime($otpData['expires_at']) < time()) {
            session()->setFlashdata('error', 'OTP has expired. Please request a new one.');
            return redirect()->to('/admin/create');
        }

        // OTP is valid, create the admin user
        $adminData = session()->get('pending_admin');
        
        if ($this->userModel->save($adminData)) {
            // Clear session data
            session()->remove('pending_admin');
            session()->remove('admin_creation_otp');
            
            session()->setFlashdata('success', 'Admin created successfully.');
            return redirect()->to('/admin');
        } else {
            session()->setFlashdata('error', 'Failed to create admin.');
            return redirect()->to('/admin/create');
        }
    }

    /**
     * Resend OTP for admin creation
     *
     * @return ResponseInterface
     */
    public function resendOtp()
    {
        // Check if we have pending admin data in session
        if (!session()->get('pending_admin')) {
            return redirect()->to('/admin/create');
        }

        // Get admin data from session
        $adminData = session()->get('pending_admin');

        // Generate new 6-digit OTP
        $otp = rand(100000, 999999);

        // Set expiration time (30 minutes from now)
        $expiresAt = date('Y-m-d H:i:s', strtotime('+30 minutes'));

        // Store OTP in session
        session()->set('admin_creation_otp', [
            'otp' => $otp,
            'expires_at' => $expiresAt
        ]);

        // Send OTP via email
        $emailSent = $this->sendOtpEmail($adminData['email'], $otp, 'creation');

        if (!$emailSent) {
            session()->setFlashdata('error', 'Failed to send OTP email. Please try again.');
        } else {
            session()->setFlashdata('success', 'OTP has been resent to your email address.');
        }

        // Redirect to OTP verification page
        return redirect()->to('/admin/verify-otp');
    }

    /**
     * Show the form to edit an admin
     *
     * @param int $id
     * @return string
     */
    public function edit($id)
    {
        $data['admin'] = $this->userModel->find($id);

        if (!$data['admin'] || $data['admin']['role'] !== 'admin') {
            throw new \CodeIgniter\Exceptions\PageNotFoundException('Admin not found');
        }

        return view('admin/edit', $data);
    }

    /**
     * Process the update of an admin
     *
     * @param int $id
     * @return ResponseInterface
     */
    public function update($id)
    {
        $admin = $this->userModel->find($id);

        if (!$admin || $admin['role'] !== 'admin') {
            throw new \CodeIgniter\Exceptions\PageNotFoundException('Admin not found');
        }

        // Get input data
        $username = $this->request->getPost('username');
        $email = $this->request->getPost('email');
        $password = $this->request->getPost('password');

        // Check if email is being changed
        $emailChanged = ($email !== $admin['email']);

        // Validate input
        $rules = [
            'username' => "required|min_length[3]|max_length[50]|is_unique[users.username,id,{$id}]",
        ];

        // Only validate email if it's being changed
        if ($emailChanged) {
            $rules['email'] = "required|valid_email|is_unique[users.email,id,{$id}]";
        }

        // Only validate password if it's being changed
        if (!empty($password)) {
            $rules['password'] = [
                'rules' => 'min_length[8]|regex_match[/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/]',
                'errors' => [
                    'min_length' => 'Password must be at least 8 characters long',
                    'regex_match' => 'Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character'
                ]
            ];
            $rules['confirm_password'] = 'matches[password]';
        }

        if (!$this->validate($rules)) {
            return view('admin/edit', [
                'admin' => $admin,
                'validation' => $this->validator,
            ]);
        }

        // If email is being changed, send OTP for verification
        if ($emailChanged) {
            // Store admin update data in session temporarily
            $updateData = [
                'id' => $id,
                'username' => $username,
                'email' => $email,
                'password' => $password
            ];
            session()->set('pending_admin_update', $updateData);

            // Generate 6-digit OTP
            $otp = rand(100000, 999999);

            // Set expiration time (30 minutes from now)
            $expiresAt = date('Y-m-d H:i:s', strtotime('+30 minutes'));

            // Store OTP in session
            session()->set('admin_update_otp', [
                'otp' => $otp,
                'expires_at' => $expiresAt
            ]);

            // Send OTP via email
            $emailSent = $this->sendOtpEmail($email, $otp, 'update');

            if (!$emailSent) {
                session()->setFlashdata('error', 'Failed to send OTP email. Please try again.');
                return redirect()->back()->withInput();
            }

            // Redirect to OTP verification page for update
            return redirect()->to('/admin/verify-update-otp/' . $id);
        }

        // If email is not being changed, proceed with update
        $userData = [
            'username' => $username
        ];

        // Only update email if it's being changed
        if ($emailChanged) {
            $userData['email'] = $email;
        }

        // Only update password if provided
        if (!empty($password)) {
            $userData['password'] = $password; // Will be hashed by model callbacks
        }

        if ($this->userModel->update($id, $userData)) {
            session()->setFlashdata('success', 'Admin updated successfully.');
            return redirect()->to('/admin');
        } else {
            session()->setFlashdata('error', 'Failed to update admin.');
            return redirect()->back()->withInput();
        }
    }

    /**
     * Display the OTP verification form for admin update
     *
     * @param int $id
     * @return string
     */
    public function verifyUpdateOtp($id)
    {
        // Check if we have pending admin update data in session
        if (!session()->get('pending_admin_update')) {
            return redirect()->to('/admin/edit/' . $id);
        }

        $data['admin_id'] = $id;
        return view('admin/verify_update_otp', $data);
    }

    /**
     * Process the OTP verification for admin update
     *
     * @param int $id
     * @return ResponseInterface
     */
    public function processUpdateOtp($id)
    {
        // Check if we have pending admin update data in session
        if (!session()->get('pending_admin_update')) {
            return redirect()->to('/admin/edit/' . $id);
        }

        // Validate input
        $rules = [
            'otp' => 'required|exact_length[6]',
        ];

        if (!$this->validate($rules)) {
            return view('admin/verify_update_otp', [
                'admin_id' => $id,
                'validation' => $this->validator,
            ]);
        }

        // Get input data
        $otp = $this->request->getPost('otp');

        // Get OTP data from session
        $otpData = session()->get('admin_update_otp');

        if (!$otpData) {
            session()->setFlashdata('error', 'OTP session expired. Please try again.');
            return redirect()->to('/admin/edit/' . $id);
        }

        // Check if OTP matches and is not expired
        if ($otpData['otp'] != $otp) {
            session()->setFlashdata('error', 'Invalid OTP. Please try again.');
            return redirect()->back()->withInput();
        }

        // Check if OTP is expired
        if (strtotime($otpData['expires_at']) < time()) {
            session()->setFlashdata('error', 'OTP has expired. Please request a new one.');
            return redirect()->to('/admin/edit/' . $id);
        }

        // OTP is valid, update the admin user
        $updateData = session()->get('pending_admin_update');
        
        // Prepare user data for update
        $userData = [
            'username' => $updateData['username'],
            'email' => $updateData['email']
        ];

        // Only update password if provided
        if (!empty($updateData['password'])) {
            $userData['password'] = $updateData['password']; // Will be hashed by model callbacks
        }

        if ($this->userModel->update($updateData['id'], $userData)) {
            // Clear session data
            session()->remove('pending_admin_update');
            session()->remove('admin_update_otp');
            
            session()->setFlashdata('success', 'Admin updated successfully.');
            return redirect()->to('/admin');
        } else {
            session()->setFlashdata('error', 'Failed to update admin.');
            return redirect()->to('/admin/edit/' . $id);
        }
    }

    /**
     * Resend OTP for admin update
     *
     * @param int $id
     * @return ResponseInterface
     */
    public function resendUpdateOtp($id)
    {
        // Check if we have pending admin update data in session
        if (!session()->get('pending_admin_update')) {
            return redirect()->to('/admin/edit/' . $id);
        }

        // Get admin update data from session
        $updateData = session()->get('pending_admin_update');

        // Generate new 6-digit OTP
        $otp = rand(100000, 999999);

        // Set expiration time (30 minutes from now)
        $expiresAt = date('Y-m-d H:i:s', strtotime('+30 minutes'));

        // Store OTP in session
        session()->set('admin_update_otp', [
            'otp' => $otp,
            'expires_at' => $expiresAt
        ]);

        // Send OTP via email
        $emailSent = $this->sendOtpEmail($updateData['email'], $otp, 'update');

        if (!$emailSent) {
            session()->setFlashdata('error', 'Failed to send OTP email. Please try again.');
            return $this->response->setJSON(['status' => 'error', 'message' => 'Failed to send OTP email.']);
        } else {
            session()->setFlashdata('success', 'OTP has been resent to your email address.');
            return $this->response->setJSON(['status' => 'success', 'message' => 'OTP resent successfully.']);
        }
    }

    /**
     * Send OTP via email
     *
     * @param string $email
     * @param string $otp
     * @param string $type (creation or update)
     * @return bool
     */
    private function sendOtpEmail($email, $otp, $type = 'creation')
    {
        $this->email->setTo($email);
        
        if ($type === 'creation') {
            $this->email->setSubject('Admin Account Creation OTP - Labourdnhdd CMS');
            $this->email->setMessage($this->getOtpEmailTemplate($otp, 'Admin Account Creation'));
        } else {
            $this->email->setSubject('Email Update OTP - Labourdnhdd CMS');
            $this->email->setMessage($this->getOtpEmailTemplate($otp, 'Email Update'));
        }

        return $this->email->send();
    }

    /**
     * Get OTP email template
     *
     * @param string $otp
     * @param string $title
     * @return string
     */
    private function getOtpEmailTemplate($otp, $title)
    {
        $template = '
        <html>
        <head>
            <style>
                body { font-family: Arial, sans-serif; }
                .container { max-width: 600px; margin: 0 auto; padding: 20px; }
                .header { background: linear-gradient(135deg, #5EC9F8 0%, #3A82D4 50%, #214D8C 100%); color: white; padding: 20px; text-align: center; }
                .content { background: #f9f9f9; padding: 30px; border: 1px solid #ddd; }
                .otp { font-size: 32px; font-weight: bold; color: #3A82D4; text-align: center; margin: 30px 0; }
                .footer { text-align: center; margin-top: 20px; color: #666; font-size: 12px; }
                .logo { max-width: 150px; margin: 0 auto 20px; }
            </style>
        </head>
        <body>
            <div class="container">
                <div class="header">
                    <img src="cid:labourdnhdd_logo" alt="Labourdnhdd Logo" class="logo">
                    <h1>Labourdnhdd - CMS</h1>
                    <p>Companies Management System</p>
                </div>
                <div class="content">
                    <h2>' . $title . '</h2>
                    <p>Hello,</p>
                    <p>';

        if ($title === 'Admin Account Creation') {
            $template .= 'You are receiving this email because an admin account is being created for you in the Labourdnhdd Companies Management System. ';
        } else {
            $template .= 'You are receiving this email because you are updating your email address in the Labourdnhdd Companies Management System. ';
        }

        $template .= 'Please use the following OTP code to verify your email address and complete the process:</p>
                    <div class="otp">' . $otp . '</div>
                    <p>This OTP will expire in 30 minutes. If you did not request this ';

        if ($title === 'Admin Account Creation') {
            $template .= 'account creation';
        } else {
            $template .= 'email update';
        }

        $template .= ', please contact your system administrator.</p>
                    <p>Thank you,<br>The Labourdnhdd Team</p>
                </div>
                <div class="footer">
                    <p>This is an automated message. Please do not reply to this email.</p>
                    <p>&copy; ' . date('Y') . ' Labourdnhdd - Companies Management System. All rights reserved.</p>
                </div>
            </div>
        </body>
        </html>';

        return $template;
    }

    /**
     * Delete an admin
     *
     * @param int $id
     * @return ResponseInterface
     */
    public function delete($id)
    {
        $admin = $this->userModel->find($id);

        if (!$admin || $admin['role'] !== 'admin') {
            throw new \CodeIgniter\Exceptions\PageNotFoundException('Admin not found');
        }

        if ($this->userModel->delete($id)) {
            session()->setFlashdata('success', 'Admin deleted successfully.');
        } else {
            session()->setFlashdata('error', 'Failed to delete admin.');
        }

        return redirect()->to('/admin');
    }
}