#!/bin/bash
# Deploy project management features from vpn to portal
# Run: sudo bash /var/www/html/portal/scripts/deploy-project-features.sh

set -e

PORTAL=/var/www/html/portal
VPN=/var/www/html/vpn
MARKER="# PROJECT_FEATURES_DEPLOYED"
WIKI_MARKER="# WIKI_ROUTES_DEPLOYED"
REASSIGN_MARKER="# REASSIGN_CLIENT_DEPLOYED"

echo "=== Deploying project management features to portal ==="

# ── 1. Migrations ────────────────────────────────────────────
echo "[1] Copying migrations..."
for f in \
    2026_05_13_112431_add_redmine_fields_to_issues_table.php \
    2026_05_13_112431_create_issue_comments_table.php \
    2026_05_13_134126_fix_issues_table_for_import.php \
    2026_05_13_143456_add_doc_and_redmine_id_to_attachments_table.php \
    2026_05_13_200000_add_type_to_documentations_table.php \
    2026_05_13_210000_add_redmine_id_to_documentations_table.php \
    2026_05_14_104759_make_projects_client_id_nullable.php; do
    if [ ! -f "$PORTAL/database/migrations/$f" ]; then
        cp "$VPN/database/migrations/$f" "$PORTAL/database/migrations/"
        chown www-data:www-data "$PORTAL/database/migrations/$f"
        echo "  copied $f"
    else
        echo "  skip (exists): $f"
    fi
done

# ── 2. Models ────────────────────────────────────────────────
echo "[2] Copying models..."
cp "$VPN/app/Models/Issue.php"          "$PORTAL/app/Models/Issue.php"
cp "$VPN/app/Models/IssueComment.php"   "$PORTAL/app/Models/IssueComment.php"
cp "$VPN/app/Models/Attachment.php"     "$PORTAL/app/Models/Attachment.php"
cp "$VPN/app/Models/Documentation.php"  "$PORTAL/app/Models/Documentation.php"
cp "$VPN/app/Models/Client.php"         "$PORTAL/app/Models/Client.php"
chown www-data:www-data \
    "$PORTAL/app/Models/Issue.php" \
    "$PORTAL/app/Models/IssueComment.php" \
    "$PORTAL/app/Models/Attachment.php" \
    "$PORTAL/app/Models/Documentation.php" \
    "$PORTAL/app/Models/Client.php"
echo "  Issue, IssueComment, Attachment, Documentation, Client updated"

# ── 2b. RedmineService (add getAllProjects) ──────────────────
echo "[2b] Updating RedmineService..."
python3 - "$PORTAL/app/Services/RedmineService.php" \
           "$VPN/app/Services/RedmineService.php" << 'INNEREOF'
import sys, re
portal_path, vpn_path = sys.argv[1], sys.argv[2]
with open(portal_path,'r') as f: portal=f.read()
with open(vpn_path,'r') as f: vpn=f.read()
if 'getAllProjects' in portal:
    print('  getAllProjects already present, skipping.')
    sys.exit(0)
m = re.search(r'(/\*\*\s*\n\s*\* 取得所有專案.*?^\s*\})', vpn, re.DOTALL|re.MULTILINE)
if not m:
    print('  ERROR: getAllProjects not found in vpn RedmineService')
    sys.exit(1)
method = '\n    ' + m.group(1).strip() + '\n'
portal = portal.replace(
    "    /**\n     * 取得單一專案詳細資訊",
    method + '\n    /**\n     * 取得單一專案詳細資訊'
)
with open(portal_path,'w') as f: f.write(portal)
print('  getAllProjects injected into RedmineService.')
INNEREOF
chown www-data:www-data "$PORTAL/app/Services/RedmineService.php"

# ── 3. Controllers ───────────────────────────────────────────
echo "[3] Copying controllers..."
cp "$VPN/app/Http/Controllers/ProjectIssueController.php" \
   "$PORTAL/app/Http/Controllers/ProjectIssueController.php"
cp "$VPN/app/Http/Controllers/DocumentationController.php" \
   "$PORTAL/app/Http/Controllers/DocumentationController.php"
cp "$VPN/app/Http/Controllers/ProjectController.php" \
   "$PORTAL/app/Http/Controllers/ProjectController.php"
chown www-data:www-data \
    "$PORTAL/app/Http/Controllers/ProjectIssueController.php" \
    "$PORTAL/app/Http/Controllers/DocumentationController.php" \
    "$PORTAL/app/Http/Controllers/ProjectController.php"
echo "  ProjectIssueController, DocumentationController, ProjectController"

# ── 4. Views ─────────────────────────────────────────────────
echo "[4] Copying views..."
mkdir -p "$PORTAL/resources/views/projects/issues"
mkdir -p "$PORTAL/resources/views/projects/docs"
mkdir -p "$PORTAL/resources/views/projects/manage"

# Projects
cp "$VPN/resources/views/projects/_nav.blade.php"              "$PORTAL/resources/views/projects/"
cp "$VPN/resources/views/projects/show.blade.php"              "$PORTAL/resources/views/projects/"
cp "$VPN/resources/views/projects/list.blade.php"              "$PORTAL/resources/views/projects/"
cp "$VPN/resources/views/projects/index.blade.php"             "$PORTAL/resources/views/projects/"
cp "$VPN/resources/views/projects/edit.blade.php"              "$PORTAL/resources/views/projects/"
cp "$VPN/resources/views/projects/create.blade.php"            "$PORTAL/resources/views/projects/"
cp "$VPN/resources/views/projects/reassign-client.blade.php"   "$PORTAL/resources/views/projects/"
cp "$VPN/resources/views/projects/manage/show.blade.php"       "$PORTAL/resources/views/projects/manage/"

# Issues
cp "$VPN/resources/views/projects/issues/index.blade.php"      "$PORTAL/resources/views/projects/issues/"
cp "$VPN/resources/views/projects/issues/show.blade.php"       "$PORTAL/resources/views/projects/issues/"
cp "$VPN/resources/views/projects/issues/create.blade.php"     "$PORTAL/resources/views/projects/issues/"
cp "$VPN/resources/views/projects/issues/edit.blade.php"       "$PORTAL/resources/views/projects/issues/"

# Docs
cp "$VPN/resources/views/projects/docs/index.blade.php"        "$PORTAL/resources/views/projects/docs/"
cp "$VPN/resources/views/projects/docs/show.blade.php"         "$PORTAL/resources/views/projects/docs/"
cp "$VPN/resources/views/projects/docs/create.blade.php"       "$PORTAL/resources/views/projects/docs/"
cp "$VPN/resources/views/projects/docs/edit.blade.php"         "$PORTAL/resources/views/projects/docs/"

# Members
cp "$VPN/resources/views/projects/members/index.blade.php"     "$PORTAL/resources/views/projects/members/"

# Other views with client?->name fix
cp "$VPN/resources/views/hosts/create.blade.php"               "$PORTAL/resources/views/hosts/"
cp "$VPN/resources/views/hosts/edit.blade.php"                 "$PORTAL/resources/views/hosts/"
cp "$VPN/resources/views/settings/maintenance-reports.blade.php" "$PORTAL/resources/views/settings/"
cp "$VPN/resources/views/settings/chat-channels.blade.php"     "$PORTAL/resources/views/settings/"
cp "$VPN/resources/views/test-reports/_form.blade.php"         "$PORTAL/resources/views/test-reports/"
cp "$VPN/resources/views/test-reports/index.blade.php"         "$PORTAL/resources/views/test-reports/"
cp "$VPN/resources/views/test-reports/show.blade.php"          "$PORTAL/resources/views/test-reports/"
cp "$VPN/resources/views/test-reports/report-pdf.blade.php"    "$PORTAL/resources/views/test-reports/"
cp "$VPN/resources/views/mails/maintenance-report.blade.php"   "$PORTAL/resources/views/mails/"

chown -R www-data:www-data \
    "$PORTAL/resources/views/projects" \
    "$PORTAL/resources/views/hosts" \
    "$PORTAL/resources/views/settings" \
    "$PORTAL/resources/views/test-reports" \
    "$PORTAL/resources/views/mails"
echo "  All views updated"

# ── 5. Bootstrap Icons CDN + favicon in layout ───────────────
echo "[5] Updating layout (Bootstrap Icons + favicon)..."
python3 - "$PORTAL/resources/views/layouts/app.blade.php" << 'PYEOF'
import sys

path = sys.argv[1]
with open(path, 'r') as f:
    content = f.read()

changed = False

if 'bootstrap-icons' not in content:
    old = '  <!-- Bootstrap 5 CDN -->\n  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">'
    new = '  <!-- Bootstrap 5 CDN -->\n  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">\n  <!-- Bootstrap Icons -->\n  <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">'
    if old in content:
        content = content.replace(old, new, 1)
        changed = True
        print('  Bootstrap Icons CDN injected.')
    else:
        print('  WARNING: Bootstrap 5 CDN anchor not found, skipping.')
else:
    print('  Bootstrap Icons already present.')

if 'rel="icon"' not in content and "rel='icon'" not in content:
    old = '  <meta charset="UTF-8">'
    new = '  <meta charset="UTF-8">\n  <link rel="icon" type="image/png" href="{{ asset(\'favicon.ico\') }}">'
    if old in content:
        content = content.replace(old, new, 1)
        changed = True
        print('  Favicon link injected.')
    else:
        print('  WARNING: charset meta tag not found, skipping favicon.')
else:
    print('  Favicon link already present.')

if changed:
    with open(path, 'w') as f:
        f.write(content)
PYEOF
chown www-data:www-data "$PORTAL/resources/views/layouts/app.blade.php"

# ── 6. Routes ────────────────────────────────────────────────
echo "[6] Injecting routes..."

# Base project features
if grep -q "$MARKER" "$PORTAL/routes/web.php"; then
    echo "  Base routes already added, skipping."
else
python3 - "$PORTAL/routes/web.php" << 'PYEOF'
import sys
path = sys.argv[1]
with open(path, 'r') as f: content = f.read()

old = "        Route::delete('projects/{project}/docs/{doc}', [DocumentationController::class, 'destroy'])->whereNumber('project')->whereNumber('doc')->name('projects.docs.destroy');"
new = """        Route::delete('projects/{project}/docs/{doc}', [DocumentationController::class, 'destroy'])->whereNumber('project')->whereNumber('doc')->name('projects.docs.destroy');
        Route::post('projects/{project}/docs/{doc}/attachments', [DocumentationController::class, 'storeAttachment'])->whereNumber('project')->whereNumber('doc')->name('projects.docs.attachments.store');
        Route::delete('projects/{project}/docs/{doc}/attachments/{attachment}', [DocumentationController::class, 'destroyAttachment'])->whereNumber('project')->whereNumber('doc')->whereNumber('attachment')->name('projects.docs.attachments.destroy');

        // # PROJECT_FEATURES_DEPLOYED
        Route::get('projects/{project}/issues', [App\\Http\\Controllers\\ProjectIssueController::class, 'index'])->whereNumber('project')->name('projects.issues.index');
        Route::get('projects/{project}/issues/create', [App\\Http\\Controllers\\ProjectIssueController::class, 'create'])->whereNumber('project')->name('projects.issues.create');
        Route::post('projects/{project}/issues', [App\\Http\\Controllers\\ProjectIssueController::class, 'store'])->whereNumber('project')->name('projects.issues.store');
        Route::get('projects/{project}/issues/{issue}', [App\\Http\\Controllers\\ProjectIssueController::class, 'show'])->whereNumber('project')->whereNumber('issue')->name('projects.issues.show');
        Route::get('projects/{project}/issues/{issue}/edit', [App\\Http\\Controllers\\ProjectIssueController::class, 'edit'])->whereNumber('project')->whereNumber('issue')->name('projects.issues.edit');
        Route::put('projects/{project}/issues/{issue}', [App\\Http\\Controllers\\ProjectIssueController::class, 'update'])->whereNumber('project')->whereNumber('issue')->name('projects.issues.update');
        Route::delete('projects/{project}/issues/{issue}', [App\\Http\\Controllers\\ProjectIssueController::class, 'destroy'])->whereNumber('project')->whereNumber('issue')->name('projects.issues.destroy');
        Route::post('projects/{project}/issues/{issue}/comments', [App\\Http\\Controllers\\ProjectIssueController::class, 'storeComment'])->whereNumber('project')->whereNumber('issue')->name('projects.issues.comments.store');
        Route::delete('projects/{project}/issues/{issue}/comments/{comment}', [App\\Http\\Controllers\\ProjectIssueController::class, 'destroyComment'])->whereNumber('project')->whereNumber('issue')->whereNumber('comment')->name('projects.issues.comments.destroy');"""

if old not in content:
    print('  ERROR: docs.destroy anchor not found'); sys.exit(1)
content = content.replace(old, new, 1)
with open(path, 'w') as f: f.write(content)
print('  Base project feature routes injected.')
PYEOF
chown www-data:www-data "$PORTAL/routes/web.php"
fi

# Wiki routes
if grep -q "$WIKI_MARKER" "$PORTAL/routes/web.php"; then
    echo "  Wiki routes already added, skipping."
else
python3 - "$PORTAL/routes/web.php" << 'PYEOF'
import sys
path = sys.argv[1]
with open(path, 'r') as f: content = f.read()

old = "        Route::delete('projects/{project}/docs/{doc}/attachments/{attachment}', [DocumentationController::class, 'destroyAttachment'])->whereNumber('project')->whereNumber('doc')->whereNumber('attachment')->name('projects.docs.attachments.destroy');"
new = """        Route::delete('projects/{project}/docs/{doc}/attachments/{attachment}', [DocumentationController::class, 'destroyAttachment'])->whereNumber('project')->whereNumber('doc')->whereNumber('attachment')->name('projects.docs.attachments.destroy');

        // wiki # WIKI_ROUTES_DEPLOYED
        Route::get('projects/{project}/wiki', [DocumentationController::class, 'index'])->whereNumber('project')->name('projects.wiki.index');
        Route::get('projects/{project}/wiki/create', [DocumentationController::class, 'create'])->whereNumber('project')->name('projects.wiki.create');
        Route::post('projects/{project}/wiki', [DocumentationController::class, 'store'])->whereNumber('project')->name('projects.wiki.store');
        Route::get('projects/{project}/wiki/{doc}', [DocumentationController::class, 'show'])->whereNumber('project')->whereNumber('doc')->name('projects.wiki.show');
        Route::get('projects/{project}/wiki/{doc}/edit', [DocumentationController::class, 'edit'])->whereNumber('project')->whereNumber('doc')->name('projects.wiki.edit');
        Route::put('projects/{project}/wiki/{doc}', [DocumentationController::class, 'update'])->whereNumber('project')->whereNumber('doc')->name('projects.wiki.update');
        Route::delete('projects/{project}/wiki/{doc}', [DocumentationController::class, 'destroy'])->whereNumber('project')->whereNumber('doc')->name('projects.wiki.destroy');
        Route::post('projects/{project}/wiki/{doc}/attachments', [DocumentationController::class, 'storeAttachment'])->whereNumber('project')->whereNumber('doc')->name('projects.wiki.attachments.store');
        Route::delete('projects/{project}/wiki/{doc}/attachments/{attachment}', [DocumentationController::class, 'destroyAttachment'])->whereNumber('project')->whereNumber('doc')->whereNumber('attachment')->name('projects.wiki.attachments.destroy');"""

if old not in content:
    print('  ERROR: docs.attachments.destroy anchor not found'); sys.exit(1)
content = content.replace(old, new, 1)
with open(path, 'w') as f: f.write(content)
print('  Wiki routes injected.')
PYEOF
chown www-data:www-data "$PORTAL/routes/web.php"
fi

# Reassign-client routes
if grep -q "$REASSIGN_MARKER" "$PORTAL/routes/web.php"; then
    echo "  Reassign-client routes already added, skipping."
else
python3 - "$PORTAL/routes/web.php" << 'PYEOF'
import sys
path = sys.argv[1]
with open(path, 'r') as f: content = f.read()

# Inject before projects/create route inside the admin middleware group
old = "        Route::get('projects/create',"
new = """        Route::get('projects/reassign-client', [ProjectController::class, 'reassignClientForm'])->name('projects.reassign-client.form'); // # REASSIGN_CLIENT_DEPLOYED
        Route::post('projects/reassign-client', [ProjectController::class, 'reassignClient'])->name('projects.reassign-client');
        Route::get('projects/create',"""

if old not in content:
    print('  ERROR: projects/create anchor not found'); sys.exit(1)
content = content.replace(old, new, 1)
with open(path, 'w') as f: f.write(content)
print('  Reassign-client routes injected.')
PYEOF
chown www-data:www-data "$PORTAL/routes/web.php"
fi

# ── 7. Schedules fix (Laravel 12: Kernel.php ignored) ────────
echo "[7] Fixing routes/console.php schedules..."
python3 - "$PORTAL/routes/console.php" << 'PYEOF'
import sys
path = sys.argv[1]
with open(path, 'r') as f: content = f.read()

if 'cve:fetch' in content:
    print('  Schedules already migrated, skipping.')
    sys.exit(0)

extra = """
// CVE 漏洞更新：每天 08:00
Schedule::command('cve:fetch')->dailyAt('08:00')->name('cve-daily-fetch')->withoutOverlapping();
// GitLab 專案同步：每 5 分鐘
Schedule::command('gitlab:sync-projects')->everyFiveMinutes()->name('gitlab-sync-projects')->withoutOverlapping();
// 主機維護報告：每小時
Schedule::command('maintenance:generate')->hourly()->name('maintenance-hourly-report')->withoutOverlapping();
// 停用到期 VPN 帳號：每天 00:30
Schedule::command('app:disable-expired-vpn-accounts')->dailyAt('00:30')->name('vpn-disable-expired')->withoutOverlapping();
"""
content = content.rstrip() + '\n' + extra
with open(path, 'w') as f: f.write(content)
print('  Schedules migrated to routes/console.php.')
PYEOF
chown www-data:www-data "$PORTAL/routes/console.php"

# ── 8. Artisan commands ──────────────────────────────────────
echo "[8] Copying artisan commands..."
mkdir -p "$PORTAL/app/Console/Commands"
cp "$VPN/app/Console/Commands/RedmineImport.php"       "$PORTAL/app/Console/Commands/RedmineImport.php"
cp "$VPN/app/Console/Commands/RedmineFixRelations.php" "$PORTAL/app/Console/Commands/RedmineFixRelations.php"
chown www-data:www-data \
    "$PORTAL/app/Console/Commands/RedmineImport.php" \
    "$PORTAL/app/Console/Commands/RedmineFixRelations.php"
echo "  RedmineImport.php, RedmineFixRelations.php"

# ── 9. Migrate + clear caches ────────────────────────────────
echo "[9] Running migrations and clearing caches..."
cd "$PORTAL"
sudo -u www-data php artisan migrate --force
sudo -u www-data php artisan view:clear
sudo -u www-data php artisan route:clear
sudo -u www-data php artisan config:clear

# ── 10. DB fixes ─────────────────────────────────────────────
echo "[10] Fixing database schema and clearing project data..."
DB_HOST=$(grep DB_HOST     "$PORTAL/.env" | cut -d= -f2 | tr -d ' \r')
DB_PORT=$(grep DB_PORT     "$PORTAL/.env" | cut -d= -f2 | tr -d ' \r')
DB_DATABASE=$(grep DB_DATABASE "$PORTAL/.env" | cut -d= -f2 | tr -d ' \r')
DB_USERNAME=$(grep DB_USERNAME "$PORTAL/.env" | cut -d= -f2 | tr -d ' \r')
DB_PASSWORD=$(grep DB_PASSWORD "$PORTAL/.env" | cut -d= -f2 | tr -d ' \r')

mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USERNAME" -p"$DB_PASSWORD" "$DB_DATABASE" << 'SQLEOF'
SET FOREIGN_KEY_CHECKS = 0;

-- Fix clients.id missing AUTO_INCREMENT
ALTER TABLE clients MODIFY id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT;

-- Clear project management data for fresh import
TRUNCATE TABLE issue_comments;
TRUNCATE TABLE issues;
TRUNCATE TABLE attachments;
TRUNCATE TABLE documentations;
TRUNCATE TABLE project_user;
TRUNCATE TABLE projects;

-- 注意：clients 是手動維護資料，不清空，由管理員自行維護
-- TRUNCATE TABLE clients;  <-- 不執行

SET FOREIGN_KEY_CHECKS = 1;
SQLEOF
echo "  Schema fixed, data cleared"

# ── 11. Import from Redmine ───────────────────────────────────
echo "[11] Importing from Redmine..."
cd "$PORTAL"
sudo -u www-data php artisan redmine:import --projects
sudo -u www-data php artisan redmine:fix-relations
sudo -u www-data php artisan redmine:import --members
sudo -u www-data php artisan redmine:import --issues
sudo -u www-data php artisan redmine:import --wiki
echo ""
echo "  Documents import (takes several minutes)..."
sudo -u www-data php artisan redmine:import --documents --redmine-password=pakeqq1234
echo ""
echo "=== All done! ==="
