/**
 * TASKMATE - Datenbank
 * ====================
 * SQLite-Datenbank mit better-sqlite3
 */

const Database = require('better-sqlite3');
const path = require('path');
const bcrypt = require('bcryptjs');
const logger = require('./utils/logger');

// Datenbank-Pfad
const DB_PATH = process.env.DB_PATH || path.join(__dirname, 'data', 'taskmate.db');

let db = null;

/**
 * Datenbank initialisieren
 */
async function initialize() {
  try {
    // Datenbank öffnen/erstellen
    db = new Database(DB_PATH);

    // WAL-Modus für bessere Performance
    db.pragma('journal_mode = WAL');
    db.pragma('foreign_keys = ON');

    // Tabellen erstellen
    createTables();

    // Standard-Benutzer erstellen (falls nicht vorhanden)
    await createDefaultUsers();

    logger.info('Datenbank initialisiert');
    return db;
  } catch (error) {
    logger.error('Datenbank-Fehler:', error);
    throw error;
  }
}

/**
 * Tabellen erstellen
 */
function createTables() {
  // Benutzer
  db.exec(`
    CREATE TABLE IF NOT EXISTS users (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      username TEXT UNIQUE NOT NULL,
      password_hash TEXT NOT NULL,
      display_name TEXT NOT NULL,
      color TEXT NOT NULL DEFAULT '#00D4FF',
      created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
      last_login DATETIME,
      failed_attempts INTEGER DEFAULT 0,
      locked_until DATETIME
    )
  `);

  // Login-Audit
  db.exec(`
    CREATE TABLE IF NOT EXISTS login_audit (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      user_id INTEGER,
      timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
      ip_address TEXT,
      success INTEGER NOT NULL,
      user_agent TEXT,
      FOREIGN KEY (user_id) REFERENCES users(id)
    )
  `);

  // Projekte
  db.exec(`
    CREATE TABLE IF NOT EXISTS projects (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      name TEXT NOT NULL,
      description TEXT,
      archived INTEGER DEFAULT 0,
      created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
      created_by INTEGER,
      FOREIGN KEY (created_by) REFERENCES users(id)
    )
  `);

  // Spalten
  db.exec(`
    CREATE TABLE IF NOT EXISTS columns (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      project_id INTEGER NOT NULL,
      name TEXT NOT NULL,
      position INTEGER NOT NULL,
      color TEXT,
      FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
    )
  `);

  // Labels
  db.exec(`
    CREATE TABLE IF NOT EXISTS labels (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      project_id INTEGER NOT NULL,
      name TEXT NOT NULL,
      color TEXT NOT NULL,
      FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
    )
  `);

  // Aufgaben
  db.exec(`
    CREATE TABLE IF NOT EXISTS tasks (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      project_id INTEGER NOT NULL,
      column_id INTEGER NOT NULL,
      title TEXT NOT NULL,
      description TEXT,
      priority TEXT DEFAULT 'medium',
      start_date DATE,
      due_date DATE,
      assigned_to INTEGER,
      time_estimate_min INTEGER,
      depends_on INTEGER,
      position INTEGER NOT NULL,
      archived INTEGER DEFAULT 0,
      created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
      created_by INTEGER,
      updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
      FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
      FOREIGN KEY (column_id) REFERENCES columns(id) ON DELETE CASCADE,
      FOREIGN KEY (assigned_to) REFERENCES users(id),
      FOREIGN KEY (depends_on) REFERENCES tasks(id) ON DELETE SET NULL,
      FOREIGN KEY (created_by) REFERENCES users(id)
    )
  `);

  // Migration: Add start_date column if it doesn't exist
  const columns = db.prepare("PRAGMA table_info(tasks)").all();
  const hasStartDate = columns.some(col => col.name === 'start_date');
  if (!hasStartDate) {
    db.exec('ALTER TABLE tasks ADD COLUMN start_date DATE');
    logger.info('Migration: start_date Spalte zu tasks hinzugefuegt');
  }

  // Migration: Add role and permissions columns to users
  const userColumns = db.prepare("PRAGMA table_info(users)").all();
  const hasRole = userColumns.some(col => col.name === 'role');
  if (!hasRole) {
    db.exec("ALTER TABLE users ADD COLUMN role TEXT DEFAULT 'user'");
    logger.info('Migration: role Spalte zu users hinzugefuegt');
  }
  const hasPermissions = userColumns.some(col => col.name === 'permissions');
  if (!hasPermissions) {
    db.exec("ALTER TABLE users ADD COLUMN permissions TEXT DEFAULT '[]'");
    logger.info('Migration: permissions Spalte zu users hinzugefuegt');
  }

  // Migration: Add email column to users
  const hasEmail = userColumns.some(col => col.name === 'email');
  if (!hasEmail) {
    db.exec("ALTER TABLE users ADD COLUMN email TEXT");
    logger.info('Migration: email Spalte zu users hinzugefuegt');
  }

  // Migration: Add repositories_base_path column to users
  const hasRepoBasePath = userColumns.some(col => col.name === 'repositories_base_path');
  if (!hasRepoBasePath) {
    db.exec("ALTER TABLE users ADD COLUMN repositories_base_path TEXT");
    logger.info('Migration: repositories_base_path Spalte zu users hinzugefuegt');
  }

  // Proposals (Vorschlaege)
  db.exec(`
    CREATE TABLE IF NOT EXISTS proposals (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      title TEXT NOT NULL,
      description TEXT,
      created_by INTEGER NOT NULL,
      created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
      approved INTEGER DEFAULT 0,
      approved_by INTEGER,
      approved_at DATETIME,
      FOREIGN KEY (created_by) REFERENCES users(id),
      FOREIGN KEY (approved_by) REFERENCES users(id)
    )
  `);

  // Proposal Votes
  db.exec(`
    CREATE TABLE IF NOT EXISTS proposal_votes (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      proposal_id INTEGER NOT NULL,
      user_id INTEGER NOT NULL,
      created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
      FOREIGN KEY (proposal_id) REFERENCES proposals(id) ON DELETE CASCADE,
      FOREIGN KEY (user_id) REFERENCES users(id)
    )
  `);

  // Unique constraint for proposal votes (one vote per user per proposal)
  db.exec(`
    CREATE UNIQUE INDEX IF NOT EXISTS idx_proposal_votes_unique
    ON proposal_votes(proposal_id, user_id)
  `);

  // Index for proposal votes
  db.exec(`
    CREATE INDEX IF NOT EXISTS idx_proposal_votes_proposal
    ON proposal_votes(proposal_id)
  `);

  // Migration: Add archived, task_id, and project_id columns to proposals
  const proposalColumns = db.prepare("PRAGMA table_info(proposals)").all();
  const hasProposalArchived = proposalColumns.some(col => col.name === 'archived');
  if (!hasProposalArchived) {
    db.exec('ALTER TABLE proposals ADD COLUMN archived INTEGER DEFAULT 0');
    logger.info('Migration: archived Spalte zu proposals hinzugefuegt');
  }
  const hasProposalTaskId = proposalColumns.some(col => col.name === 'task_id');
  if (!hasProposalTaskId) {
    db.exec('ALTER TABLE proposals ADD COLUMN task_id INTEGER REFERENCES tasks(id) ON DELETE SET NULL');
    logger.info('Migration: task_id Spalte zu proposals hinzugefuegt');
  }
  const hasProposalProjectId = proposalColumns.some(col => col.name === 'project_id');
  if (!hasProposalProjectId) {
    db.exec('ALTER TABLE proposals ADD COLUMN project_id INTEGER REFERENCES projects(id) ON DELETE CASCADE');
    logger.info('Migration: project_id Spalte zu proposals hinzugefuegt');
  }

  // Migration: Add filter_category column to columns
  const columnColumns = db.prepare("PRAGMA table_info(columns)").all();
  const hasFilterCategory = columnColumns.some(col => col.name === 'filter_category');
  if (!hasFilterCategory) {
    db.exec("ALTER TABLE columns ADD COLUMN filter_category TEXT DEFAULT 'in_progress'");
    logger.info('Migration: filter_category Spalte zu columns hinzugefuegt');

    // Set default values for existing columns based on position
    const projects = db.prepare('SELECT id FROM projects').all();
    for (const project of projects) {
      const cols = db.prepare('SELECT id, position FROM columns WHERE project_id = ? ORDER BY position').all(project.id);
      if (cols.length > 0) {
        // First column = open
        db.prepare("UPDATE columns SET filter_category = 'open' WHERE id = ?").run(cols[0].id);
        // Last column = completed
        if (cols.length > 1) {
          db.prepare("UPDATE columns SET filter_category = 'completed' WHERE id = ?").run(cols[cols.length - 1].id);
        }
      }
    }
    logger.info('Migration: Standard-Filterkategorien fuer bestehende Spalten gesetzt');
  }

  // Task-Labels (Verknüpfung)
  db.exec(`
    CREATE TABLE IF NOT EXISTS task_labels (
      task_id INTEGER NOT NULL,
      label_id INTEGER NOT NULL,
      PRIMARY KEY (task_id, label_id),
      FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE,
      FOREIGN KEY (label_id) REFERENCES labels(id) ON DELETE CASCADE
    )
  `);

  // Task-Assignees (Mehrfachzuweisung von Mitarbeitern)
  db.exec(`
    CREATE TABLE IF NOT EXISTS task_assignees (
      task_id INTEGER NOT NULL,
      user_id INTEGER NOT NULL,
      PRIMARY KEY (task_id, user_id),
      FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE,
      FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
    )
  `);

  // Unteraufgaben
  db.exec(`
    CREATE TABLE IF NOT EXISTS subtasks (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      task_id INTEGER NOT NULL,
      title TEXT NOT NULL,
      completed INTEGER DEFAULT 0,
      position INTEGER NOT NULL,
      FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE
    )
  `);

  // Kommentare
  db.exec(`
    CREATE TABLE IF NOT EXISTS comments (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      task_id INTEGER NOT NULL,
      user_id INTEGER NOT NULL,
      content TEXT NOT NULL,
      created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
      FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE,
      FOREIGN KEY (user_id) REFERENCES users(id)
    )
  `);

  // Anhänge
  db.exec(`
    CREATE TABLE IF NOT EXISTS attachments (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      task_id INTEGER NOT NULL,
      filename TEXT NOT NULL,
      original_name TEXT NOT NULL,
      mime_type TEXT NOT NULL,
      size_bytes INTEGER NOT NULL,
      uploaded_by INTEGER,
      uploaded_at DATETIME DEFAULT CURRENT_TIMESTAMP,
      FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE,
      FOREIGN KEY (uploaded_by) REFERENCES users(id)
    )
  `);

  // Links
  db.exec(`
    CREATE TABLE IF NOT EXISTS links (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      task_id INTEGER NOT NULL,
      title TEXT,
      url TEXT NOT NULL,
      created_by INTEGER,
      created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
      FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE,
      FOREIGN KEY (created_by) REFERENCES users(id)
    )
  `);

  // Aufgaben-Vorlagen
  db.exec(`
    CREATE TABLE IF NOT EXISTS task_templates (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      project_id INTEGER NOT NULL,
      name TEXT NOT NULL,
      title_template TEXT,
      description TEXT,
      priority TEXT,
      labels TEXT,
      subtasks TEXT,
      time_estimate_min INTEGER,
      FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
    )
  `);

  // Historie
  db.exec(`
    CREATE TABLE IF NOT EXISTS history (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      task_id INTEGER NOT NULL,
      user_id INTEGER NOT NULL,
      action TEXT NOT NULL,
      field_changed TEXT,
      old_value TEXT,
      new_value TEXT,
      timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
      FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE,
      FOREIGN KEY (user_id) REFERENCES users(id)
    )
  `);

  // Einstellungen
  db.exec(`
    CREATE TABLE IF NOT EXISTS settings (
      key TEXT PRIMARY KEY,
      value TEXT
    )
  `);

  // Anwendungen (Git-Repositories pro Projekt)
  db.exec(`
    CREATE TABLE IF NOT EXISTS applications (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      project_id INTEGER NOT NULL UNIQUE,
      local_path TEXT NOT NULL,
      gitea_repo_url TEXT,
      gitea_repo_owner TEXT,
      gitea_repo_name TEXT,
      default_branch TEXT DEFAULT 'main',
      last_sync DATETIME,
      created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
      created_by INTEGER,
      FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
      FOREIGN KEY (created_by) REFERENCES users(id)
    )
  `);

  // Benachrichtigungen (Inbox)
  db.exec(`
    CREATE TABLE IF NOT EXISTS notifications (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      user_id INTEGER NOT NULL,
      type TEXT NOT NULL,
      title TEXT NOT NULL,
      message TEXT,
      task_id INTEGER,
      project_id INTEGER,
      proposal_id INTEGER,
      actor_id INTEGER,
      is_read INTEGER DEFAULT 0,
      is_persistent INTEGER DEFAULT 0,
      created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
      FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
      FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE,
      FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
      FOREIGN KEY (proposal_id) REFERENCES proposals(id) ON DELETE CASCADE,
      FOREIGN KEY (actor_id) REFERENCES users(id) ON DELETE SET NULL
    )
  `);

  // Indizes für Performance
  db.exec(`
    CREATE INDEX IF NOT EXISTS idx_tasks_project ON tasks(project_id);
    CREATE INDEX IF NOT EXISTS idx_tasks_column ON tasks(column_id);
    CREATE INDEX IF NOT EXISTS idx_tasks_assigned ON tasks(assigned_to);
    CREATE INDEX IF NOT EXISTS idx_tasks_due_date ON tasks(due_date);
    CREATE INDEX IF NOT EXISTS idx_subtasks_task ON subtasks(task_id);
    CREATE INDEX IF NOT EXISTS idx_comments_task ON comments(task_id);
    CREATE INDEX IF NOT EXISTS idx_history_task ON history(task_id);
    CREATE INDEX IF NOT EXISTS idx_attachments_task ON attachments(task_id);
    CREATE INDEX IF NOT EXISTS idx_links_task ON links(task_id);
    CREATE INDEX IF NOT EXISTS idx_task_labels_task ON task_labels(task_id);
    CREATE INDEX IF NOT EXISTS idx_task_labels_label ON task_labels(label_id);
    CREATE INDEX IF NOT EXISTS idx_notifications_user ON notifications(user_id);
    CREATE INDEX IF NOT EXISTS idx_notifications_user_read ON notifications(user_id, is_read);
    CREATE INDEX IF NOT EXISTS idx_notifications_created ON notifications(created_at);
    CREATE INDEX IF NOT EXISTS idx_applications_project ON applications(project_id);
  `);

  logger.info('Datenbank-Tabellen erstellt');
}

/**
 * Standard-Benutzer erstellen
 */
async function createDefaultUsers() {
  const existingUsers = db.prepare('SELECT COUNT(*) as count FROM users').get();

  if (existingUsers.count === 0) {
    // Benutzer aus Umgebungsvariablen
    const user1 = {
      username: process.env.USER1_USERNAME || 'user1',
      password: process.env.USER1_PASSWORD || 'changeme123',
      displayName: process.env.USER1_DISPLAYNAME || 'Benutzer 1',
      color: process.env.USER1_COLOR || '#00D4FF'
    };

    const user2 = {
      username: process.env.USER2_USERNAME || 'user2',
      password: process.env.USER2_PASSWORD || 'changeme456',
      displayName: process.env.USER2_DISPLAYNAME || 'Benutzer 2',
      color: process.env.USER2_COLOR || '#FF9500'
    };

    const insertUser = db.prepare(`
      INSERT INTO users (username, password_hash, display_name, color, role, permissions)
      VALUES (?, ?, ?, ?, ?, ?)
    `);

    // Admin-Benutzer
    const adminUser = {
      username: 'admin',
      password: 'Kx9#mP2$vL7@nQ4!wR',
      displayName: 'Administrator',
      color: '#8B5CF6'
    };

    // Passwoerter hashen und Benutzer erstellen
    const hash1 = await bcrypt.hash(user1.password, 12);
    const hash2 = await bcrypt.hash(user2.password, 12);
    const hashAdmin = await bcrypt.hash(adminUser.password, 12);

    insertUser.run(user1.username, hash1, user1.displayName, user1.color, 'user', '[]');
    insertUser.run(user2.username, hash2, user2.displayName, user2.color, 'user', '[]');
    insertUser.run(adminUser.username, hashAdmin, adminUser.displayName, adminUser.color, 'admin', '[]');

    logger.info('Standard-Benutzer und Admin erstellt');

    // Standard-Projekt erstellen
    const projectResult = db.prepare(`
      INSERT INTO projects (name, description, created_by)
      VALUES (?, ?, ?)
    `).run('Mein erstes Projekt', 'Willkommen bei TaskMate!', 1);

    const projectId = projectResult.lastInsertRowid;

    // Standard-Spalten erstellen
    const insertColumn = db.prepare(`
      INSERT INTO columns (project_id, name, position, color)
      VALUES (?, ?, ?, ?)
    `);

    insertColumn.run(projectId, 'Offen', 0, null);
    insertColumn.run(projectId, 'In Arbeit', 1, null);
    insertColumn.run(projectId, 'Erledigt', 2, null);

    // Standard-Labels erstellen
    const insertLabel = db.prepare(`
      INSERT INTO labels (project_id, name, color)
      VALUES (?, ?, ?)
    `);

    insertLabel.run(projectId, 'Bug', '#DC2626');
    insertLabel.run(projectId, 'Feature', '#059669');
    insertLabel.run(projectId, 'Dokumentation', '#3182CE');

    logger.info('Standard-Projekt mit Spalten und Labels erstellt');
  }
}

/**
 * Datenbank-Instanz abrufen
 */
function getDb() {
  if (!db) {
    throw new Error('Datenbank nicht initialisiert');
  }
  return db;
}

/**
 * Datenbank schließen
 */
function close() {
  if (db) {
    db.close();
    logger.info('Datenbank geschlossen');
  }
}

module.exports = {
  initialize,
  getDb,
  close
};
