import { db, encryptedDb } from '../config/secureDatabase'
import { Employee } from '@skillmate/shared'
import { v4 as uuidv4 } from 'uuid'

export interface EmployeeInput {
  firstName: string
  lastName: string
  employeeNumber?: string | null
  photo?: string | null
  position?: string
  officialTitle?: string | null
  department: string
  email: string
  phone?: string | null
  mobile?: string | null
  office?: string | null
  availability?: string
  clearance?: { level?: string; validUntil?: string | Date | null; issuedDate?: string | Date | null } | null
  skills?: Array<{ id: string; level?: any; verified?: boolean; verifiedBy?: string | null; verifiedDate?: string | Date | null }>
  languages?: Array<{ code: string; level: string }>
  specializations?: string[]
}

export function getAllWithDetails(): Employee[] {
  const emps = (encryptedDb.getAllEmployees() as any[]) || []
  if (emps.length === 0) return []
  const ids = emps.map((e: any) => e.id)
  const placeholders = ids.map(() => '?').join(',')

  // Batch fetch related data
  const skillsRows = db.prepare(`
    SELECT es.employee_id, s.id, s.name, s.category, es.level, es.verified, es.verified_by, es.verified_date
    FROM employee_skills es
    JOIN skills s ON es.skill_id = s.id
    WHERE es.employee_id IN (${placeholders})
  `).all(...ids) as any[]

  const langRows = db.prepare(`
    SELECT employee_id, language, proficiency, certified, certificate_type, is_native, can_interpret
    FROM language_skills
    WHERE employee_id IN (${placeholders})
  `).all(...ids) as any[]

  const specRows = db.prepare(`
    SELECT employee_id, name FROM specializations WHERE employee_id IN (${placeholders})
  `).all(...ids) as any[]

  const skillsByEmp = new Map<string, any[]>()
  for (const r of skillsRows) {
    if (!skillsByEmp.has(r.employee_id)) skillsByEmp.set(r.employee_id, [])
    skillsByEmp.get(r.employee_id)!.push(r)
  }
  const langsByEmp = new Map<string, any[]>()
  for (const r of langRows) {
    if (!langsByEmp.has(r.employee_id)) langsByEmp.set(r.employee_id, [])
    langsByEmp.get(r.employee_id)!.push(r)
  }
  const specsByEmp = new Map<string, string[]>()
  for (const r of specRows) {
    if (!specsByEmp.has(r.employee_id)) specsByEmp.set(r.employee_id, [])
    specsByEmp.get(r.employee_id)!.push(r.name)
  }

  const mapProf = (p: string): 'basic' | 'fluent' | 'native' | 'business' => {
    const m: Record<string, any> = { A1: 'basic', A2: 'basic', B1: 'business', B2: 'business', C1: 'fluent', C2: 'fluent', Muttersprache: 'native', native: 'native', fluent: 'fluent', advanced: 'business', intermediate: 'business', basic: 'basic' }
    return m[p] || 'basic'
  }

  return emps.map((emp: any) => {
    const s = skillsByEmp.get(emp.id) || []
    const l = langsByEmp.get(emp.id) || []
    const sp = specsByEmp.get(emp.id) || []
    return {
      id: emp.id,
      firstName: emp.first_name,
      lastName: emp.last_name,
      employeeNumber: (emp.employee_number && !String(emp.employee_number).startsWith('EMP')) ? emp.employee_number : undefined,
      photo: emp.photo,
      position: emp.position,
      officialTitle: emp.official_title || undefined,
      department: emp.department,
      email: emp.email,
      phone: emp.phone,
      mobile: emp.mobile,
      office: emp.office,
      availability: emp.availability,
      skills: s.map((r: any) => ({ id: r.id, name: r.name, category: r.category, level: r.level, verified: Boolean(r.verified), verifiedBy: r.verified_by, verifiedDate: r.verified_date ? new Date(r.verified_date) : undefined })),
      languages: l.map((r: any) => ({ code: r.language, level: mapProf(r.proficiency) })),
      clearance: emp.clearance_level && emp.clearance_valid_until && emp.clearance_issued_date ? { level: emp.clearance_level, validUntil: new Date(emp.clearance_valid_until), issuedDate: new Date(emp.clearance_issued_date) } : undefined,
      specializations: sp,
      createdAt: new Date(emp.created_at),
      updatedAt: new Date(emp.updated_at),
      createdBy: emp.created_by,
      updatedBy: emp.updated_by
    } as Employee
  })
}

export function getByIdWithDetails(id: string): Employee | null {
  const emp = encryptedDb.getEmployee(id) as any
  if (!emp) return null
  return buildEmployeeWithDetails(emp)
}

function buildEmployeeWithDetails(emp: any): Employee {
  const skills = db.prepare(`
    SELECT s.id, s.name, s.category, es.level, es.verified, es.verified_by, es.verified_date
    FROM employee_skills es
    JOIN skills s ON es.skill_id = s.id
    WHERE es.employee_id = ?
  `).all(emp.id)

  const languages = db.prepare(`
    SELECT language, proficiency, certified, certificate_type, is_native, can_interpret
    FROM language_skills
    WHERE employee_id = ?
  `).all(emp.id)

  const specializations = db.prepare(`
    SELECT name FROM specializations WHERE employee_id = ?
  `).all(emp.id).map((s: any) => s.name)

  const mapProf = (p: string): 'basic' | 'fluent' | 'native' | 'business' => {
    const m: Record<string, any> = { A1: 'basic', A2: 'basic', B1: 'business', B2: 'business', C1: 'fluent', C2: 'fluent', Muttersprache: 'native', native: 'native', fluent: 'fluent', advanced: 'business', intermediate: 'business', basic: 'basic' }
    return m[p] || 'basic'
  }

  return {
    id: emp.id,
    firstName: emp.first_name,
    lastName: emp.last_name,
    employeeNumber: (emp.employee_number && !String(emp.employee_number).startsWith('EMP')) ? emp.employee_number : undefined,
    photo: emp.photo,
    position: emp.position,
    department: emp.department,
    email: emp.email,
    phone: emp.phone,
    mobile: emp.mobile,
    office: emp.office,
    availability: emp.availability,
    officialTitle: emp.official_title || undefined,
    skills: skills.map((s: any) => ({
      id: s.id,
      name: s.name,
      category: s.category,
      level: s.level,
      verified: Boolean(s.verified),
      verifiedBy: s.verified_by,
      verifiedDate: s.verified_date ? new Date(s.verified_date) : undefined
    })),
    languages: languages.map((l: any) => ({
      code: l.language,
      level: mapProf(l.proficiency)
    })),
    clearance: emp.clearance_level && emp.clearance_valid_until && emp.clearance_issued_date ? {
      level: emp.clearance_level,
      validUntil: new Date(emp.clearance_valid_until),
      issuedDate: new Date(emp.clearance_issued_date)
    } : undefined,
    specializations,
    createdAt: new Date(emp.created_at),
    updatedAt: new Date(emp.updated_at),
    createdBy: emp.created_by,
    updatedBy: emp.updated_by
  }
}

export function createEmployee(input: EmployeeInput, actorUserId: string): { id: string } {
  const now = new Date().toISOString()
  const employeeId = uuidv4()
  const position = input.position || 'Teammitglied'
  const officialTitle = input.officialTitle || null
  const phone = input.phone || 'Nicht angegeben'
  const availability = input.availability || 'available'
  const employeeNumber = input.employeeNumber || `EMP${Date.now()}`

  const tx = db.transaction(() => {
    // Uniqueness check for employee number
    const existingEmployee = db.prepare('SELECT id FROM employees WHERE employee_number = ?').get(employeeNumber)
    if (existingEmployee) {
      const err: any = new Error('Employee number already exists')
      err.statusCode = 409
      throw err
    }

    encryptedDb.insertEmployee({
      id: employeeId,
      first_name: input.firstName,
      last_name: input.lastName,
      employee_number: employeeNumber,
      photo: input.photo || null,
      position,
      official_title: officialTitle,
      department: input.department,
      email: input.email,
      phone,
      mobile: input.mobile || null,
      office: input.office || null,
      availability,
      clearance_level: input.clearance?.level || null,
      clearance_valid_until: input.clearance?.validUntil || null,
      clearance_issued_date: input.clearance?.issuedDate || null,
      created_at: now,
      updated_at: now,
      created_by: actorUserId,
      updated_by: actorUserId,
    })

    if (input.skills && input.skills.length > 0) {
      const stmt = db.prepare(`
        INSERT INTO employee_skills (employee_id, skill_id, level, verified, verified_by, verified_date)
        VALUES (?, ?, ?, ?, ?, ?)
      `)
      const checkSkillExists = db.prepare('SELECT id FROM skills WHERE id = ?')
      for (const s of input.skills) {
        const exists = checkSkillExists.get(s.id)
        if (!exists) continue
        stmt.run(employeeId, s.id, typeof s.level === 'number' ? s.level : (parseInt(String(s.level)) || null), s.verified ? 1 : 0, s.verifiedBy || null, s.verifiedDate || null)
      }
    }

    if (input.languages && input.languages.length > 0) {
      const stmt = db.prepare(`
        INSERT INTO language_skills (id, employee_id, language, proficiency, certified, certificate_type, is_native, can_interpret)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?)
      `)
      for (const l of input.languages) {
        stmt.run(uuidv4(), employeeId, l.code, l.level, 0, null, 0, 0)
      }
    }

    if (input.specializations && input.specializations.length > 0) {
      const stmt = db.prepare('INSERT INTO specializations (id, employee_id, name) VALUES (?, ?, ?)')
      for (const name of input.specializations) {
        stmt.run(uuidv4(), employeeId, name)
      }
    }
  })

  tx()
  return { id: employeeId }
}

export function updateEmployee(id: string, input: EmployeeInput, actorUserId: string) {
  const now = new Date().toISOString()

  const tx = db.transaction(() => {
    const existing = db.prepare('SELECT id FROM employees WHERE id = ?').get(id)
    if (!existing) {
      const err: any = new Error('Employee not found')
      err.statusCode = 404
      throw err
    }

    db.prepare(`
      UPDATE employees SET
        first_name = ?, last_name = ?, position = ?, official_title = ?, department = ?,
        email = ?, email_hash = ?, phone = ?, phone_hash = ?, 
        mobile = ?, office = ?, availability = ?,
        clearance_level = ?, clearance_valid_until = ?, clearance_issued_date = ?,
        updated_at = ?, updated_by = ?
      WHERE id = ?
    `).run(
      input.firstName, input.lastName, input.position || 'Teammitglied', input.officialTitle || null, input.department,
      // encryption handled in secure db layer caller; here store encrypted values already in input? Route prepares with FieldEncryption
      input.email, // already encrypted by route layer
      null, // email_hash set by route if needed
      input.phone || '',
      null, // phone_hash set by route if needed
      input.mobile || null,
      input.office || null,
      input.availability || 'available',
      input.clearance?.level || null,
      input.clearance?.validUntil || null,
      input.clearance?.issuedDate || null,
      now,
      actorUserId,
      id
    )

    if (input.skills) {
      db.prepare('DELETE FROM employee_skills WHERE employee_id = ?').run(id)
      if (input.skills.length > 0) {
        const insert = db.prepare(`
          INSERT INTO employee_skills (employee_id, skill_id, level, verified, verified_by, verified_date)
          VALUES (?, ?, ?, ?, ?, ?)
        `)
        const checkSkillExists = db.prepare('SELECT id FROM skills WHERE id = ?')
        for (const s of input.skills) {
          const exists = checkSkillExists.get(s.id)
          if (!exists) continue
          insert.run(
            id,
            s.id,
            typeof s.level === 'number' ? s.level : (parseInt(String(s.level)) || null),
            s.verified ? 1 : 0,
            s.verifiedBy || null,
            s.verifiedDate || null
          )
        }
      }
    }
  })

  tx()
}

export function deleteEmployee(id: string) {
  const tx = db.transaction(() => {
    const existing = db.prepare('SELECT id FROM employees WHERE id = ?').get(id)
    if (!existing) {
      const err: any = new Error('Employee not found')
      err.statusCode = 404
      throw err
    }
    db.prepare('DELETE FROM employee_skills WHERE employee_id = ?').run(id)
    db.prepare('DELETE FROM language_skills WHERE employee_id = ?').run(id)
    db.prepare('DELETE FROM specializations WHERE employee_id = ?').run(id)
    db.prepare('DELETE FROM employees WHERE id = ?').run(id)
  })
  tx()
}
