/**
 * TASKMATE - Coding Routes
 * ========================
 * Verwaltung von Server-Anwendungen mit Claude/Codex Integration
 */

const express = require('express');
const router = express.Router();
const fs = require('fs');
const path = require('path');
const { getDb } = require('../database');
const logger = require('../utils/logger');
const gitService = require('../services/gitService');

/**
 * Prüft ob ein Pfad ein Server-Pfad (Linux) ist
 */
function isServerPath(localPath) {
  return localPath && localPath.startsWith('/');
}

/**
 * Schreibt CLAUDE.md in ein Verzeichnis
 */
function writeCLAUDEmd(directoryPath, content) {
  if (!content || !directoryPath) return false;

  try {
    const claudePath = path.join(directoryPath, 'CLAUDE.md');
    fs.writeFileSync(claudePath, content, 'utf8');
    logger.info(`CLAUDE.md geschrieben: ${claudePath}`);
    return true;
  } catch (e) {
    logger.error('CLAUDE.md schreiben fehlgeschlagen:', e);
    return false;
  }
}

/**
 * Liest CLAUDE.md aus einem Verzeichnis
 */
function readCLAUDEmd(directoryPath) {
  if (!directoryPath) {
    logger.info('readCLAUDEmd: No directoryPath provided');
    return null;
  }

  try {
    const claudePath = path.join(directoryPath, 'CLAUDE.md');
    logger.info(`readCLAUDEmd: Checking path ${claudePath}`);
    
    if (fs.existsSync(claudePath)) {
      const content = fs.readFileSync(claudePath, 'utf8');
      logger.info(`readCLAUDEmd: Successfully read ${content.length} characters from ${claudePath}`);
      return content;
    } else {
      logger.info(`readCLAUDEmd: File does not exist: ${claudePath}`);
    }
  } catch (e) {
    logger.error('CLAUDE.md lesen fehlgeschlagen:', e);
  }
  return null;
}

/**
 * GET /api/coding/directories
 * Alle Coding-Verzeichnisse abrufen
 */
router.get('/directories', (req, res) => {
  try {
    const db = getDb();
    const directories = db.prepare(`
      SELECT cd.*, u.display_name as creator_name
      FROM coding_directories cd
      LEFT JOIN users u ON cd.created_by = u.id
      ORDER BY cd.position ASC, cd.name ASC
    `).all();

    res.json(directories.map(dir => {
      // CLAUDE.md aus dem Dateisystem lesen falls vorhanden
      let claudeMdFromDisk = null;
      if (isServerPath(dir.local_path)) {
        claudeMdFromDisk = readCLAUDEmd(dir.local_path);
        // Fallback: Wenn Pfad /home/claude-dev/TaskMate ist, versuche /app/taskmate-source
        if (!claudeMdFromDisk && dir.local_path === '/home/claude-dev/TaskMate') {
          logger.info('Trying fallback path for TaskMate: /app/taskmate-source');
          claudeMdFromDisk = readCLAUDEmd('/app/taskmate-source');
        }
      }

      return {
        id: dir.id,
        name: dir.name,
        localPath: dir.local_path,
        description: dir.description,
        color: dir.color,
        claudeInstructions: dir.claude_instructions,
        claudeMdFromDisk: claudeMdFromDisk,
        hasCLAUDEmd: !!claudeMdFromDisk,
        giteaRepoUrl: dir.gitea_repo_url,
        giteaRepoOwner: dir.gitea_repo_owner,
        giteaRepoName: dir.gitea_repo_name,
        defaultBranch: dir.default_branch,
        lastSync: dir.last_sync,
        position: dir.position,
        createdAt: dir.created_at,
        createdBy: dir.created_by,
        creatorName: dir.creator_name
      };
    }));
  } catch (error) {
    logger.error('Fehler beim Abrufen der Coding-Verzeichnisse:', error);
    res.status(500).json({ error: 'Interner Serverfehler' });
  }
});

/**
 * POST /api/coding/directories
 * Neues Coding-Verzeichnis erstellen
 */
router.post('/directories', (req, res) => {
  try {
    const { name, localPath, description, color, claudeInstructions, giteaRepoUrl, giteaRepoOwner, giteaRepoName, defaultBranch } = req.body;

    if (!name || !localPath) {
      return res.status(400).json({ error: 'Name und Server-Pfad sind erforderlich' });
    }

    const db = getDb();

    // Prüfe ob Pfad bereits existiert
    const existing = db.prepare('SELECT id FROM coding_directories WHERE local_path = ?').get(localPath);
    if (existing) {
      return res.status(400).json({ error: 'Diese Anwendung ist bereits registriert' });
    }

    // Höchste Position ermitteln
    const maxPos = db.prepare('SELECT COALESCE(MAX(position), -1) as max FROM coding_directories').get().max;

    const result = db.prepare(`
      INSERT INTO coding_directories (name, local_path, description, color, claude_instructions, gitea_repo_url, gitea_repo_owner, gitea_repo_name, default_branch, position, created_by)
      VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `).run(
      name,
      localPath,
      description || null,
      color || '#4F46E5',
      null, // claudeInstructions wird nicht mehr gespeichert
      giteaRepoUrl || null,
      giteaRepoOwner || null,
      giteaRepoName || null,
      defaultBranch || 'main',
      maxPos + 1,
      req.user.id
    );

    const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(result.lastInsertRowid);

    // Ordner erstellen falls nicht vorhanden
    let directoryCreated = false;
    if (isServerPath(localPath) && !fs.existsSync(localPath)) {
      try {
        fs.mkdirSync(localPath, { recursive: true });
        directoryCreated = true;
        logger.info(`Anwendungsordner erstellt: ${localPath}`);
      } catch (e) {
        logger.error('Ordner erstellen fehlgeschlagen:', e);
      }
    }

    // CLAUDE.md wird nicht mehr geschrieben - nur readonly
    let claudeMdWritten = false;

    logger.info(`Coding-Anwendung erstellt: ${name} (${localPath})`);

    // CLAUDE.md aus dem Dateisystem lesen für aktuelle Anzeige
    const claudeMdFromDisk = isServerPath(directory.local_path) ? readCLAUDEmd(directory.local_path) : null;

    res.status(201).json({
      id: directory.id,
      name: directory.name,
      localPath: directory.local_path,
      description: directory.description,
      color: directory.color,
      claudeInstructions: directory.claude_instructions,
      claudeMdFromDisk: claudeMdFromDisk,
      hasCLAUDEmd: !!claudeMdFromDisk,
      giteaRepoUrl: directory.gitea_repo_url,
      giteaRepoOwner: directory.gitea_repo_owner,
      giteaRepoName: directory.gitea_repo_name,
      defaultBranch: directory.default_branch,
      position: directory.position,
      createdAt: directory.created_at,
      directoryCreated,
      claudeMdWritten
    });
  } catch (error) {
    logger.error('Fehler beim Erstellen der Coding-Anwendung:', error);
    res.status(500).json({ error: 'Interner Serverfehler' });
  }
});

/**
 * PUT /api/coding/directories/:id
 * Coding-Anwendung aktualisieren
 */
router.put('/directories/:id', (req, res) => {
  try {
    const { id } = req.params;
    const { name, localPath, description, color, claudeInstructions, giteaRepoUrl, giteaRepoOwner, giteaRepoName, defaultBranch, position } = req.body;

    const db = getDb();

    const existing = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
    if (!existing) {
      return res.status(404).json({ error: 'Anwendung nicht gefunden' });
    }

    // Prüfe ob neuer Pfad bereits von anderem Eintrag verwendet wird
    if (localPath && localPath !== existing.local_path) {
      const pathExists = db.prepare('SELECT id FROM coding_directories WHERE local_path = ? AND id != ?').get(localPath, id);
      if (pathExists) {
        return res.status(400).json({ error: 'Dieser Server-Pfad ist bereits registriert' });
      }
    }

    db.prepare(`
      UPDATE coding_directories SET
        name = COALESCE(?, name),
        local_path = COALESCE(?, local_path),
        description = ?,
        color = COALESCE(?, color),
        claude_instructions = ?,
        gitea_repo_url = ?,
        gitea_repo_owner = ?,
        gitea_repo_name = ?,
        default_branch = COALESCE(?, default_branch),
        position = COALESCE(?, position)
      WHERE id = ?
    `).run(
      name || null,
      localPath || null,
      description !== undefined ? description : existing.description,
      color || null,
      null, // claudeInstructions wird nicht mehr aktualisiert
      giteaRepoUrl !== undefined ? giteaRepoUrl : existing.gitea_repo_url,
      giteaRepoOwner !== undefined ? giteaRepoOwner : existing.gitea_repo_owner,
      giteaRepoName !== undefined ? giteaRepoName : existing.gitea_repo_name,
      defaultBranch || null,
      position !== undefined ? position : null,
      id
    );

    const updated = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
    const finalPath = updated.local_path;

    // Ordner erstellen falls nicht vorhanden
    let directoryCreated = false;
    if (isServerPath(finalPath) && !fs.existsSync(finalPath)) {
      try {
        fs.mkdirSync(finalPath, { recursive: true });
        directoryCreated = true;
        logger.info(`Anwendungsordner erstellt: ${finalPath}`);
      } catch (e) {
        logger.error('Ordner erstellen fehlgeschlagen:', e);
      }
    }

    // CLAUDE.md wird nicht mehr geschrieben - nur readonly
    let claudeMdWritten = false;

    logger.info(`Coding-Anwendung aktualisiert: ${updated.name}`);

    // CLAUDE.md aus dem Dateisystem lesen für aktuelle Anzeige
    const claudeMdFromDisk = isServerPath(updated.local_path) ? readCLAUDEmd(updated.local_path) : null;

    res.json({
      id: updated.id,
      name: updated.name,
      localPath: updated.local_path,
      description: updated.description,
      color: updated.color,
      claudeInstructions: updated.claude_instructions,
      claudeMdFromDisk: claudeMdFromDisk,
      hasCLAUDEmd: !!claudeMdFromDisk,
      giteaRepoUrl: updated.gitea_repo_url,
      giteaRepoOwner: updated.gitea_repo_owner,
      giteaRepoName: updated.gitea_repo_name,
      defaultBranch: updated.default_branch,
      position: updated.position,
      createdAt: updated.created_at,
      directoryCreated,
      claudeMdWritten
    });
  } catch (error) {
    logger.error('Fehler beim Aktualisieren der Coding-Anwendung:', error);
    res.status(500).json({ error: 'Interner Serverfehler' });
  }
});

/**
 * DELETE /api/coding/directories/:id
 * Coding-Anwendung löschen
 */
router.delete('/directories/:id', (req, res) => {
  try {
    const { id } = req.params;
    const db = getDb();

    const existing = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
    if (!existing) {
      return res.status(404).json({ error: 'Anwendung nicht gefunden' });
    }

    db.prepare('DELETE FROM coding_directories WHERE id = ?').run(id);

    logger.info(`Coding-Anwendung gelöscht: ${existing.name}`);

    res.json({ message: 'Anwendung gelöscht' });
  } catch (error) {
    logger.error('Fehler beim Löschen der Coding-Anwendung:', error);
    res.status(500).json({ error: 'Interner Serverfehler' });
  }
});

/**
 * GET /api/coding/directories/:id/status
 * Git-Status eines Verzeichnisses abrufen
 */
router.get('/directories/:id/status', (req, res) => {
  try {
    const { id } = req.params;
    const db = getDb();

    const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
    if (!directory) {
      return res.status(404).json({ error: 'Anwendung nicht gefunden' });
    }

    const localPath = directory.local_path;

    // Prüfe ob es ein Git-Repository ist
    if (!gitService.isGitRepository(localPath)) {
      return res.json({
        isGitRepo: false,
        message: 'Kein Git-Repository'
      });
    }

    const status = gitService.getStatus(localPath);

    if (!status.success) {
      return res.status(500).json({ error: status.error });
    }

    res.json({
      isGitRepo: true,
      branch: status.branch,
      hasChanges: status.hasChanges,
      changes: status.changes,
      ahead: status.ahead,
      behind: status.behind,
      isClean: status.isClean
    });
  } catch (error) {
    logger.error('Fehler beim Abrufen des Git-Status:', error);
    res.status(500).json({ error: 'Interner Serverfehler' });
  }
});

/**
 * POST /api/coding/directories/:id/fetch
 * Git Fetch ausführen
 */
router.post('/directories/:id/fetch', (req, res) => {
  try {
    const { id } = req.params;
    const db = getDb();

    const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
    if (!directory) {
      return res.status(404).json({ error: 'Anwendung nicht gefunden' });
    }

    const result = gitService.fetchRemote(directory.local_path);

    if (!result.success) {
      return res.status(500).json({ error: result.error });
    }

    // Last sync aktualisieren
    db.prepare('UPDATE coding_directories SET last_sync = CURRENT_TIMESTAMP WHERE id = ?').run(id);

    logger.info(`Git fetch ausgeführt für: ${directory.name}`);

    res.json({ success: true, message: 'Fetch erfolgreich' });
  } catch (error) {
    logger.error('Fehler beim Git Fetch:', error);
    res.status(500).json({ error: 'Interner Serverfehler' });
  }
});

/**
 * POST /api/coding/directories/:id/pull
 * Git Pull ausführen
 */
router.post('/directories/:id/pull', (req, res) => {
  try {
    const { id } = req.params;
    const db = getDb();

    const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
    if (!directory) {
      return res.status(404).json({ error: 'Anwendung nicht gefunden' });
    }

    const result = gitService.pullChanges(directory.local_path, { branch: directory.default_branch });

    if (!result.success) {
      return res.status(500).json({ error: result.error });
    }

    // Last sync aktualisieren
    db.prepare('UPDATE coding_directories SET last_sync = CURRENT_TIMESTAMP WHERE id = ?').run(id);

    logger.info(`Git pull ausgeführt für: ${directory.name}`);

    res.json({ success: true, message: 'Pull erfolgreich', output: result.output });
  } catch (error) {
    logger.error('Fehler beim Git Pull:', error);
    res.status(500).json({ error: 'Interner Serverfehler' });
  }
});

/**
 * POST /api/coding/directories/:id/push
 * Git Push ausführen
 */
router.post('/directories/:id/push', (req, res) => {
  try {
    const { id } = req.params;
    const { force } = req.body;
    const db = getDb();

    const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
    if (!directory) {
      return res.status(404).json({ error: 'Anwendung nicht gefunden' });
    }

    const result = gitService.pushWithUpstream(directory.local_path, directory.default_branch, 'origin', force);

    if (!result.success) {
      return res.status(500).json({ error: result.error });
    }

    // Last sync aktualisieren
    db.prepare('UPDATE coding_directories SET last_sync = CURRENT_TIMESTAMP WHERE id = ?').run(id);

    logger.info(`Git push ausgeführt für: ${directory.name}`);

    res.json({ success: true, message: 'Push erfolgreich', output: result.output });
  } catch (error) {
    logger.error('Fehler beim Git Push:', error);
    res.status(500).json({ error: 'Interner Serverfehler' });
  }
});

/**
 * POST /api/coding/directories/:id/commit
 * Git Commit ausführen
 */
router.post('/directories/:id/commit', (req, res) => {
  try {
    const { id } = req.params;
    const { message } = req.body;
    const db = getDb();

    if (!message || message.trim() === '') {
      return res.status(400).json({ error: 'Commit-Nachricht erforderlich' });
    }

    const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
    if (!directory) {
      return res.status(404).json({ error: 'Anwendung nicht gefunden' });
    }

    // Stage all changes
    const stageResult = gitService.stageAll(directory.local_path);
    if (!stageResult.success) {
      return res.status(500).json({ error: stageResult.error });
    }

    // Commit with author info
    const author = {
      name: req.user.display_name || req.user.username,
      email: req.user.email || `${req.user.username}@taskmate.local`
    };

    const result = gitService.commit(directory.local_path, message, author);

    if (!result.success) {
      return res.status(500).json({ error: result.error });
    }

    logger.info(`Git commit ausgeführt für: ${directory.name} - "${message}"`);

    res.json({ success: true, message: 'Commit erfolgreich', output: result.output });
  } catch (error) {
    logger.error('Fehler beim Git Commit:', error);
    res.status(500).json({ error: 'Interner Serverfehler' });
  }
});

/**
 * GET /api/coding/directories/:id/branches
 * Branches abrufen
 */
router.get('/directories/:id/branches', (req, res) => {
  try {
    const { id } = req.params;
    const db = getDb();

    const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
    if (!directory) {
      return res.status(404).json({ error: 'Anwendung nicht gefunden' });
    }

    const result = gitService.getBranches(directory.local_path);

    if (!result.success) {
      return res.status(500).json({ error: result.error });
    }

    res.json({ branches: result.branches });
  } catch (error) {
    logger.error('Fehler beim Abrufen der Branches:', error);
    res.status(500).json({ error: 'Interner Serverfehler' });
  }
});

/**
 * POST /api/coding/directories/:id/checkout
 * Branch wechseln
 */
router.post('/directories/:id/checkout', (req, res) => {
  try {
    const { id } = req.params;
    const { branch } = req.body;
    const db = getDb();

    if (!branch) {
      return res.status(400).json({ error: 'Branch erforderlich' });
    }

    const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
    if (!directory) {
      return res.status(404).json({ error: 'Anwendung nicht gefunden' });
    }

    const result = gitService.checkoutBranch(directory.local_path, branch);

    if (!result.success) {
      return res.status(500).json({ error: result.error });
    }

    logger.info(`Branch gewechselt für ${directory.name}: ${branch}`);

    res.json({ success: true, message: `Gewechselt zu Branch: ${branch}` });
  } catch (error) {
    logger.error('Fehler beim Branch-Wechsel:', error);
    res.status(500).json({ error: 'Interner Serverfehler' });
  }
});

/**
 * POST /api/coding/validate-path
 * Pfad validieren
 */
router.post('/validate-path', (req, res) => {
  try {
    const { path: localPath } = req.body;

    if (!localPath) {
      return res.status(400).json({ error: 'Pfad erforderlich' });
    }

    // Nur Server-Pfade können validiert werden
    if (isServerPath(localPath)) {
      const containerPath = gitService.windowsToContainerPath(localPath);
      const exists = fs.existsSync(containerPath);
      const isGitRepo = exists && gitService.isGitRepository(localPath);

      res.json({
        valid: true,
        exists,
        isGitRepo,
        isServerPath: true
      });
    } else {
      // Windows-Pfad kann nicht serverseitig validiert werden
      res.json({
        valid: true,
        exists: null,
        isGitRepo: null,
        isServerPath: false,
        message: 'Windows-Pfade können nicht serverseitig validiert werden'
      });
    }
  } catch (error) {
    logger.error('Fehler bei der Pfad-Validierung:', error);
    res.status(500).json({ error: 'Interner Serverfehler' });
  }
});

/**
 * GET /api/coding/directories/:id/commits
 * Commit-Historie abrufen
 */
router.get('/directories/:id/commits', (req, res) => {
  try {
    const { id } = req.params;
    const limit = parseInt(req.query.limit) || 20;
    const db = getDb();

    const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
    if (!directory) {
      return res.status(404).json({ error: 'Anwendung nicht gefunden' });
    }

    const result = gitService.getCommitHistory(directory.local_path, limit);

    if (!result.success) {
      return res.status(500).json({ error: result.error });
    }

    res.json({ commits: result.commits });
  } catch (error) {
    logger.error('Fehler beim Abrufen der Commit-Historie:', error);
    res.status(500).json({ error: 'Interner Serverfehler' });
  }
});

/**
 * GET /api/coding/directories/:id/usage
 * Aktuelle Verbrauchsdaten abrufen (simuliert)
 */
router.get('/directories/:id/usage', (req, res) => {
  try {
    const { id } = req.params;
    const db = getDb();

    const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
    if (!directory) {
      return res.status(404).json({ error: 'Anwendung nicht gefunden' });
    }

    // Simulierte Verbrauchsdaten generieren
    const usage = {
      cpu_percent: Math.random() * 100,
      memory_mb: Math.floor(Math.random() * 4096),
      disk_read_mb: Math.random() * 100,
      disk_write_mb: Math.random() * 50,
      network_recv_mb: Math.random() * 10,
      network_sent_mb: Math.random() * 10,
      process_count: Math.floor(Math.random() * 20) + 1,
      timestamp: new Date()
    };

    // Speichere in Datenbank für Historie
    db.prepare(`
      INSERT INTO coding_usage (directory_id, cpu_percent, memory_mb, disk_read_mb, 
                                disk_write_mb, network_recv_mb, network_sent_mb, process_count)
      VALUES (?, ?, ?, ?, ?, ?, ?, ?)
    `).run(id, usage.cpu_percent, usage.memory_mb, usage.disk_read_mb, 
           usage.disk_write_mb, usage.network_recv_mb, usage.network_sent_mb, usage.process_count);

    res.json({ usage });
  } catch (error) {
    logger.error('Fehler beim Abrufen der Verbrauchsdaten:', error);
    res.status(500).json({ error: 'Interner Serverfehler' });
  }
});

/**
 * GET /api/coding/directories/:id/usage/history
 * Historische Verbrauchsdaten abrufen
 */
router.get('/directories/:id/usage/history', (req, res) => {
  try {
    const { id } = req.params;
    const hours = parseInt(req.query.hours) || 24;
    const db = getDb();

    const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
    if (!directory) {
      return res.status(404).json({ error: 'Anwendung nicht gefunden' });
    }

    const history = db.prepare(`
      SELECT * FROM coding_usage 
      WHERE directory_id = ? 
        AND timestamp > datetime('now', '-${hours} hours')
      ORDER BY timestamp DESC
      LIMIT 100
    `).all(id);

    res.json({ history });
  } catch (error) {
    logger.error('Fehler beim Abrufen der Verbrauchshistorie:', error);
    res.status(500).json({ error: 'Interner Serverfehler' });
  }
});

module.exports = router;
