<?php
declare(strict_types=1);

/*
|--------------------------------------------------------------------------
| TechStackBase – Bulk User Upload (SKELETON)
|--------------------------------------------------------------------------
| - CSV upload only
| - First name & surname REQUIRED
| - Two-pass processing (validate → insert)
| - Full hierarchy, RSP, company enforcement
| - Audited per user + per batch
*/

require_once __DIR__ . '/../system/bootstrap.php';
require_once __DIR__ . '/../system/auth.php';
require_once __DIR__ . '/../system/response.php';
require_once __DIR__ . '/../system/audit.php';
require_once __DIR__ . '/../system/mail.php';

header('Content-Type: application/json');

/* =========================
   AUTH
   ========================= */
$actor = require_auth($pdo);

if (!in_array($actor['role_key'], ['super_admin','platform_admin','rsp_admin'], true)) {
    error_forbidden('Insufficient privileges');
}

/* =========================
   DRY RUN VALIDATION
   ========================= */
   
$dryRun = false;

if (
    (isset($_GET['dry_run']) && $_GET['dry_run'] === 'true') ||
    (isset($_POST['dry_run']) && $_POST['dry_run'] === '1')
) {
    $dryRun = true;
}

/* =========================
   SEND EMAIL INVITES
   =========================*/
   
$sendInvites = false;

if (
    (isset($_GET['send_invites']) && $_GET['send_invites'] === 'true') ||
    (isset($_POST['send_invites']) && $_POST['send_invites'] === '1')
) {
    $sendInvites = true;
}

/* =========================
   FILE INPUT
   ========================= */
if (
    !isset($_FILES['file']) ||
    $_FILES['file']['error'] !== UPLOAD_ERR_OK
) {
    error_bad_request('CSV file is required');
}

$tmpPath = $_FILES['file']['tmp_name'];

$handle = fopen($tmpPath, 'r');
if (!$handle) {
    error_internal('Unable to read uploaded file');
}

/* =========================
   CSV HEADERS
   ========================= */
$header = fgetcsv($handle);
if (!$header) {
    error_bad_request('Empty CSV file');
}

$header = array_map('trim', $header);

$requiredHeaders = [
    'email',
    'first_name',
    'last_name',
    'role_key',
    'rsp_id',
    'company_id',
    'status',
    'email_verified',
    'password'
];

foreach ($requiredHeaders as $h) {
    if (!in_array($h, $header, true)) {
        error_bad_request("Missing required column: {$h}");
    }
}

$colIndex = array_flip($header);

/* =========================
   VALIDATION HELPER
   ========================= */
   
function is_valid_email(string $email): bool
{
    return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}

function role_rank(string $role): int
{
    static $ranks = [
        'user'           => 1,
        'company_admin'  => 2,
        'rsp_admin'      => 3,
        'platform_admin' => 4,
        'super_admin'    => 5
    ];
    return $ranks[$role] ?? 0;
}

function valid_status(?string $status): bool
{
    return in_array($status, ['active','locked','disabled'], true);
}

function valid_email_verified($v): bool
{
    return $v === '0' || $v === '1' || $v === 0 || $v === 1;
}

/* =========================
   PASS 1 — PARSE & VALIDATE
   ========================= */
$rows = [];
$errors = [];
$rowNumber = 1; // header = row 1

while (($data = fgetcsv($handle)) !== false) {
    $rowNumber++;

    $row = [];
    foreach ($colIndex as $col => $idx) {
        $row[$col] = isset($data[$idx]) ? trim((string)$data[$idx]) : '';
    }

    /* ---------- Mandatory fields ---------- */
    if ($row['email'] === '') {
        $errors[] = ['row' => $rowNumber, 'email' => '', 'reason' => 'Email is required'];
        continue;
    }

    if ($row['first_name'] === '') {
        $errors[] = ['row' => $rowNumber, 'email' => $row['email'], 'reason' => 'First name is required'];
        continue;
    }

    if ($row['last_name'] === '') {
        $errors[] = ['row' => $rowNumber, 'email' => $row['email'], 'reason' => 'Last name is required'];
        continue;
    }

    /* ---------- Add validation hooks ---------- */
/* ---------- Email format ---------- */
if (!is_valid_email($row['email'])) {
    $errors[] = [
        'row'    => $rowNumber,
        'email'  => $row['email'],
        'reason' => 'Invalid email format'
    ];
    continue;
}

/* ---------- Role ---------- */
$row['role_key'] = strtolower($row['role_key']);

if (!role_rank($row['role_key'])) {
    $errors[] = [
        'row'    => $rowNumber,
        'email'  => $row['email'],
        'reason' => 'Invalid role'
    ];
    continue;
}

if (role_rank($row['role_key']) >= role_rank($actor['role_key'])) {
    $errors[] = [
        'row'    => $rowNumber,
        'email'  => $row['email'],
        'reason' => 'Cannot assign equal or higher role'
    ];
    continue;
}

/* ---------- RSP ---------- */
$rspId = (int)$row['rsp_id'];
if ($rspId <= 0) {
    $errors[] = [
        'row'    => $rowNumber,
        'email'  => $row['email'],
        'reason' => 'Invalid rsp_id'
    ];
    continue;
}

/* RSP admin locked to own RSP */
if ($actor['role_key'] === 'rsp_admin' && (int)$actor['rsp_id'] !== $rspId) {
    $errors[] = [
        'row'    => $rowNumber,
        'email'  => $row['email'],
        'reason' => 'RSP outside your scope'
    ];
    continue;
}

/* ---------- Company ---------- */
$companyId = (int)$row['company_id'];
if ($companyId <= 0) {
    $errors[] = [
        'row'    => $rowNumber,
        'email'  => $row['email'],
        'reason' => 'Invalid company_id'
    ];
    continue;
}

$stmt = $pdo->prepare("
    SELECT id
    FROM companies
    WHERE id = ?
      AND rsp_id = ?
      AND deleted_at IS NULL
    LIMIT 1
");
$stmt->execute([$companyId, $rspId]);

if (!$stmt->fetchColumn()) {
    $errors[] = [
        'row'    => $rowNumber,
        'email'  => $row['email'],
        'reason' => 'Company does not belong to RSP'
    ];
    continue;
}

/* ---------- Status ---------- */
$row['status'] = $row['status'] !== ''
    ? strtolower($row['status'])
    : 'active';

if (!valid_status($row['status'])) {
    $errors[] = [
        'row'    => $rowNumber,
        'email'  => $row['email'],
        'reason' => 'Invalid status'
    ];
    continue;
}

/* ---------- Email verified ---------- */
$row['email_verified'] = $row['email_verified'] !== ''
    ? (int)$row['email_verified']
    : 0;

if (!valid_email_verified($row['email_verified'])) {
    $errors[] = [
        'row'    => $rowNumber,
        'email'  => $row['email'],
        'reason' => 'Invalid email_verified value'
    ];
    continue;
}

/* ---------- Email uniqueness ---------- */
$stmt = $pdo->prepare("
    SELECT id
    FROM users
    WHERE email = ?
    LIMIT 1
");
$stmt->execute([$row['email']]);

if ($stmt->fetchColumn()) {
    $errors[] = [
        'row'    => $rowNumber,
        'email'  => $row['email'],
        'reason' => 'Email already exists'
    ];
    continue;
}

/* ---------- Password ---------- */
if ($row['password'] !== '' && strlen($row['password']) < 8) {
    $errors[] = [
        'row'    => $rowNumber,
        'email'  => $row['email'],
        'reason' => 'Password too short (min 8 chars)'
    ];
    continue;
}


    $rows[] = [
        'row'  => $rowNumber,
        'data' => $row
    ];
}

fclose($handle);

if (!$rows && $errors) {
    success('No valid rows', [
        'summary' => [
            'total'   => $rowNumber - 1,
            'created' => 0,
            'failed'  => count($errors)
        ],
        'errors' => $errors
    ]);
}

/* =========================
   PASSWORD LOGIC
   ========================= */
   
function generate_password(int $length = 12): string
{
    $chars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789!@#$%';
    $password = '';
    for ($i = 0; $i < $length; $i++) {
        $password .= $chars[random_int(0, strlen($chars) - 1)];
    }
    return $password;
}

/* =========================
   PASS 2 — INSERT USERS
   ========================= */

$created = 0;
$failed  = count($errors);

if ($dryRun) {
    // Simulate success for all valid rows
    $created = count($rows);

} else {

    foreach ($rows as $item) {
        $row = $item['data'];

        $pdo->beginTransaction();

        try {
            /* ---------- Password ---------- */
            $plainPassword = $row['password'] !== ''
                ? $row['password']
                : generate_password();

            $passwordHash = password_hash($plainPassword, PASSWORD_DEFAULT);

            /* ---------- INSERT USER ---------- */
            $stmt = $pdo->prepare("
                INSERT INTO users (
                    email,
                    first_name,
                    last_name,
                    role_key,
                    rsp_id,
                    company_id,
                    status,
                    email_verified,
                    password_hash,
                    created_at
                ) VALUES (
                    :email,
                    :first_name,
                    :last_name,
                    :role_key,
                    :rsp_id,
                    :company_id,
                    :status,
                    :email_verified,
                    :password_hash,
                    NOW()
                )
            ");

            $stmt->execute([
                ':email'          => $row['email'],
                ':first_name'     => $row['first_name'],
                ':last_name'      => $row['last_name'],
                ':role_key'       => $row['role_key'],
                ':rsp_id'         => (int)$row['rsp_id'],
                ':company_id'     => (int)$row['company_id'],
                ':status'         => $row['status'],
                ':email_verified' => (int)$row['email_verified'],
                ':password_hash'  => $passwordHash
            ]);

            $newUserId = (int)$pdo->lastInsertId();

            /* ---------- AUDIT (PER USER) ---------- */
            audit_log(
                $pdo,
                $actor,
                'create',
                'user',
                $newUserId,
                [
                    'bulk_upload' => true,
                    'email'       => $row['email'],
                    'rsp_id'      => (int)$row['rsp_id'],
                    'company_id'  => (int)$row['company_id'],
                    'role_key'    => $row['role_key']
                ]
            );

            $pdo->commit();
            
            /* Send email attemnpt */
            
            if (
                !$dryRun &&
                $sendInvites &&
                $generatedPassword !== null &&
                (int)$row['email_verified'] === 0
            ) {
                try {
                    send_invite_email(
                        $row['email'],
                        $row['first_name'],
                        $generatedPassword
                    );
                } catch (Throwable $e) {
                    error_log('INVITE EMAIL FAILED: ' . $row['email']);
                }
            }
            
            if (
                !$dryRun &&
                $sendInvites &&
                $generatedPassword !== null
            ) {
                audit_log(
                    $pdo,
                    $actor,
                    'invite_sent',
                    'user',
                    $newUserId,
                    [
                        'bulk_upload' => true,
                        'email' => $row['email']
                    ]
                );
            }

            $created++;

        /* ---------- OPTIONAL: store generated password ---------- */
            $generatedPassword = null;
    
            if ($row['password'] !== '') {
                $plainPassword = $row['password'];
            } else {
                $plainPassword = generate_password();
                $generatedPassword = $plainPassword;
            }

        } catch (Throwable $e) {
            $pdo->rollBack();

            $failed++;
            $errors[] = [
                'row'    => $item['row'],
                'email'  => $row['email'],
                'reason' => 'Insert failed'
            ];

            error_log('BULK USER INSERT FAILED: ' . $e->getMessage());
        }
    }
}

/* =========================
   AUDIT — BATCH SUMMARY
   ========================= */
if (!$dryRun) {
    audit_log(
        $pdo,
        $actor,
        'bulk_create',
        'user',
        null,
        [
            'total_rows' => $rowNumber - 1,
            'created'    => $created,
            'failed'     => $failed
        ]
    );
}

/* =========================
   RESPONSE
   ========================= */
success($dryRun ? 'Dry-run completed' : 'Bulk upload completed', [
    'dry_run' => $dryRun,
    'summary' => [
        'total'   => $rowNumber - 1,
        'created' => $created,
        'failed'  => $failed
    ],
    'errors' => $errors
]);

