<?php
namespace App\Controllers;

use App\Core\Database;
use App\Core\ProfileGuard;

class ProfileController
{
    protected function db()
    {
        return Database::getInstance();
    }

    private function startSession(): void
    {
        if (session_status() !== PHP_SESSION_ACTIVE) {
            session_start();
        }
    }

    private function requireLogin(): void
    {
        $this->startSession();

        if (empty($_SESSION['user_id'])) {
            header("Location: /easychair/login");
            exit;
        }

        if (empty($_SESSION['conference_id'])) {
            header("Location: /easychair/select-conference");
            exit;
        }
    }

    private function role(): string
    {
        return (string)($_SESSION['conference_role'] ?? $_SESSION['role'] ?? $_SESSION['user_role'] ?? '');
    }

    private function conference(): array
    {
        $stmt = $this->db()->prepare("SELECT * FROM conferences WHERE id=? LIMIT 1");
        $stmt->execute([(int)$_SESSION['conference_id']]);
        $c = $stmt->fetch(\PDO::FETCH_ASSOC);

        if (!$c) {
            exit("Conference not found.");
        }

        return $c;
    }

    private function ensureProfile(array $conference): array
    {
        $userId = (int)$_SESSION['user_id'];
        $confId = (int)$conference['id'];

        $stmt = $this->db()->prepare("
            SELECT *
            FROM user_profiles
            WHERE user_id=?
              AND conference_id=?
            LIMIT 1
        ");
        $stmt->execute([$userId, $confId]);
        $profile = $stmt->fetch(\PDO::FETCH_ASSOC);

        if ($profile) {
            return $profile;
        }

        $stmt = $this->db()->prepare("
            INSERT INTO user_profiles
            (user_id, org_id, conference_id, updated_by)
            VALUES (?, ?, ?, ?)
        ");
        $stmt->execute([
            $userId,
            (int)$conference['org_id'],
            $confId,
            $userId
        ]);

        $stmt = $this->db()->prepare("
            SELECT *
            FROM user_profiles
            WHERE user_id=?
              AND conference_id=?
            LIMIT 1
        ");
        $stmt->execute([$userId, $confId]);

        return $stmt->fetch(\PDO::FETCH_ASSOC) ?: [];
    }

    private function columnExists(string $table, string $column): bool
    {
        $stmt = $this->db()->prepare("
            SELECT COUNT(*)
            FROM INFORMATION_SCHEMA.COLUMNS
            WHERE TABLE_SCHEMA=DATABASE()
              AND TABLE_NAME=?
              AND COLUMN_NAME=?
        ");
        $stmt->execute([$table, $column]);
        return (int)$stmt->fetchColumn() > 0;
    }


    private function roleForConference(int $userId, int $conferenceId): string
    {
        $stmt = $this->db()->prepare("
            SELECT r.code
            FROM user_conferences uc
            JOIN roles r ON r.id=uc.role_id
            WHERE uc.user_id=?
              AND uc.conference_id=?
            LIMIT 1
        ");
        $stmt->execute([$userId, $conferenceId]);
        return (string)($stmt->fetchColumn() ?: '');
    }

    private function profileFieldRules(int $conferenceId, string $roleCode): array
    {
        $stmt = $this->db()->prepare("
            SELECT *
            FROM profile_field_rules
            WHERE conference_id=?
              AND role_code=?
              AND is_visible=1
            ORDER BY sort_order, field_label
        ");
        $stmt->execute([$conferenceId, $roleCode]);
        $rows = $stmt->fetchAll(\PDO::FETCH_ASSOC);

        $map = [];
        foreach ($rows as $r) {
            $map[$r['field_key']] = $r;
        }

        return $map;
    }

    private function customFields(int $conferenceId, string $roleCode): array
    {
        $stmt = $this->db()->prepare("
            SELECT *
            FROM profile_custom_fields
            WHERE conference_id=?
              AND is_visible=1
              AND role_code IN ('all', ?)
            ORDER BY sort_order, field_label
        ");
        $stmt->execute([$conferenceId, $roleCode]);
        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
    }

    private function customValues(int $userId, int $conferenceId): array
    {
        $stmt = $this->db()->prepare("
            SELECT *
            FROM profile_custom_values
            WHERE user_id=?
              AND conference_id=?
        ");
        $stmt->execute([$userId, $conferenceId]);
        $rows = $stmt->fetchAll(\PDO::FETCH_ASSOC);

        $map = [];
        foreach ($rows as $r) {
            $map[(int)$r['custom_field_id']] = $r['field_value'];
        }

        return $map;
    }


    private function uploadFile(string $field, string $folder, array $allowed): ?string
    {
        if (empty($_FILES[$field]['name']) || !is_uploaded_file($_FILES[$field]['tmp_name'])) {
            return null;
        }

        $ext = strtolower(pathinfo($_FILES[$field]['name'], PATHINFO_EXTENSION));
        $ext = preg_replace('/[^a-z0-9]/', '', $ext);

        if (!in_array($ext, $allowed, true)) {
            exit("Invalid file type for {$field}.");
        }

        $dir = BASE_PATH . '/public/storage/profiles/' . (int)$_SESSION['user_id'] . '/' . $folder;

        if (!is_dir($dir)) {
            mkdir($dir, 0775, true);
        }

        $name = $field . '_' . date('YmdHis') . '_' . rand(1000,9999) . '.' . $ext;

        if (!move_uploaded_file($_FILES[$field]['tmp_name'], $dir . '/' . $name)) {
            exit("Could not upload {$field}.");
        }

        return 'profiles/' . (int)$_SESSION['user_id'] . '/' . $folder . '/' . $name;
    }

    public function index()
    {
        $this->requireLogin();

        $conference = $this->conference();
        $profile = $this->ensureProfile($conference);

        $nameCols = [];
        foreach (['first_name', 'firstname', 'name'] as $c) {
            if ($this->columnExists('users', $c)) {
                $nameCols[] = $c;
            }
        }

        $stmt = $this->db()->prepare("
            SELECT u.*, r.code AS role_code, r.name AS role_name
            FROM users u
            LEFT JOIN user_conferences uc 
                   ON uc.user_id=u.id
                  AND uc.conference_id=?
            LEFT JOIN roles r ON r.id=uc.role_id
            WHERE u.id=?
            LIMIT 1
        ");
        $stmt->execute([(int)$conference['id'], (int)$_SESSION['user_id']]);
        $user = $stmt->fetch(\PDO::FETCH_ASSOC) ?: [];

        $roleCode = $this->roleForConference((int)$_SESSION['user_id'], (int)$conference['id']);
        if ($roleCode === '') {
            $roleCode = $this->role() ?: 'author';
        }

        $fieldRules = $this->profileFieldRules((int)$conference['id'], $roleCode);
        $customFields = $this->customFields((int)$conference['id'], $roleCode);
        $customValues = $this->customValues((int)$_SESSION['user_id'], (int)$conference['id']);
        $missingFields = [];
        try {
            $guard = new ProfileGuard();
            $missingFields = $guard->missingFields((int)$_SESSION['user_id'], (int)$conference['id']);
        } catch (\Throwable $e) {
            $missingFields = [];
        }

        ob_start();
        require BASE_PATH . '/app/views/profile/index.php';
        $content = ob_get_clean();

        $role = $this->role();

        if (in_array($role, ['super_admin','org_admin','admin','organizer','conference_chair','track_chair'], true)) {
            require BASE_PATH . '/app/views/layouts/admin_layout.php';
        } elseif ($role === 'reviewer') {
            require BASE_PATH . '/app/views/layouts/reviewer_layout.php';
        } else {
            require BASE_PATH . '/app/views/layouts/author_layout.php';
        }
    }

    public function save()
    {
        $this->requireLogin();

        $conference = $this->conference();
        $profile = $this->ensureProfile($conference);

        $imagePath = $this->uploadFile('profile_image', 'images', ['jpg','jpeg','png','webp']);
        $cvPath = $this->uploadFile('cv_file', 'cv', ['pdf','doc','docx']);

        $fields = [
            'phone','mobile','country','city',
            'affiliation','affiliation_ar','college','department','academic_rank',
            'major','specialization','education_level','highest_degree','degree_university','graduation_year',
            'orcid','scopus_id','google_scholar','personal_website','linkedin_url',
            'research_interests','keywords','bio','bio_ar',
            'reviewer_expertise','review_keywords','preferred_tracks','conflict_of_interest',
            'author_notes'
        ];

        $sets = [];
        $params = [];

        foreach ($fields as $f) {
            if ($this->columnExists('user_profiles', $f)) {
                $sets[] = "{$f}=?";
                $params[] = trim((string)($_POST[$f] ?? ''));
            }
        }

        if ($this->columnExists('user_profiles', 'reviewer_capacity')) {
            $reviewerCapacity = (int)($_POST['reviewer_capacity'] ?? 0);
            if ($reviewerCapacity < 0) {
                $reviewerCapacity = 0;
            }

            $sets[] = "reviewer_capacity=?";
            $params[] = $reviewerCapacity;
        }

        if ($imagePath !== null && $this->columnExists('user_profiles', 'profile_image')) {
            $sets[] = "profile_image=?";
            $params[] = $imagePath;
        }

        if ($cvPath !== null && $this->columnExists('user_profiles', 'cv_file')) {
            $sets[] = "cv_file=?";
            $params[] = $cvPath;
        }

        if ($this->columnExists('user_profiles', 'updated_by')) {
            $sets[] = "updated_by=?";
            $params[] = (int)$_SESSION['user_id'];
        }

        if ($this->columnExists('user_profiles', 'is_profile_complete')) {
            $sets[] = "is_profile_complete = CASE
                WHEN COALESCE(affiliation,'') <> ''
                 AND COALESCE(major,'') <> ''
                 AND COALESCE(specialization,'') <> ''
                 AND COALESCE(education_level,'') <> ''
                THEN 1 ELSE 0
            END";
        }

        if (!$sets) {
            exit("No profile columns available for update.");
        }

        $params[] = (int)$profile['id'];
        $params[] = (int)$_SESSION['user_id'];
        $params[] = (int)$conference['id'];

        $stmt = $this->db()->prepare("
            UPDATE user_profiles
            SET " . implode(",\n                ", $sets) . "
            WHERE id=?
              AND user_id=?
              AND conference_id=?
        ");
        $stmt->execute($params);

        $_SESSION['flash_success'] = "Profile saved successfully.";
        header("Location: /easychair/profile?saved=1");
        exit;
    }
}
