'use strict'

/**
 * equipeController.js — CRUD para Equipe Virtual (Fase 12)
 *
 * Recursos:
 *   accounts        — colaboradores internos
 *   sectors         — setores operacionais
 *   team_members    — vínculo conta ↔ setor
 *   sector_brains   — cérebro de conhecimento por setor
 *   inbox_interna   — mensagens internas (Human API, escalações, colaboração)
 */

const bcrypt    = require('bcryptjs')
const { query, queryOne, execute } = require('../database/postgres')

// ─── helpers ───────────────────────────────────────────────────────────────

function tid(req) { return req.tenantId || 1 }

function ok(res, data)           { return res.json(data) }
function err(res, status, msg)   { return res.status(status).json({ error: msg }) }
function serverErr(res, e, tag)  {
  console.error(`[equipe] ${tag}:`, e)
  return res.status(500).json({ error: 'Erro interno' })
}

// ─── ACCOUNTS ───────────────────────────────────────────────────────────────

async function listAccounts(req, res) {
  try {
    const { role, active } = req.query
    let sql = `
      SELECT a.id, a.name, a.email, a.role, a.phone, a.phone_connected,
             a.availability, a.avatar_url, a.active, a.created_at,
             a.nw_team_id, a.nw_sector_id,
             COALESCE(
               json_agg(
                 json_build_object(
                   'sector_id', tm.sector_id,
                   'sector_name', s.name,
                   'function', tm.function,
                   'is_primary', tm.is_primary,
                   'on_duty', tm.on_duty
                 )
               ) FILTER (WHERE tm.id IS NOT NULL), '[]'
             ) AS sectors
      FROM accounts a
      LEFT JOIN team_members tm ON tm.account_id = a.id
      LEFT JOIN sectors s ON s.id = tm.sector_id
      WHERE a.tenant_id = $1
    `
    const params = [tid(req)]
    if (role)   { params.push(role);           sql += ` AND a.role = $${params.length}` }
    if (active !== undefined) { params.push(active === 'true'); sql += ` AND a.active = $${params.length}` }
    sql += ` GROUP BY a.id ORDER BY a.name`
    const rows = await query(sql, params)
    ok(res, rows)
  } catch (e) { serverErr(res, e, 'listAccounts') }
}

async function getAccount(req, res) {
  try {
    const row = await queryOne(
      `SELECT id, name, email, role, phone, phone_connected, availability, avatar_url,
              active, created_at, nw_team_id, nw_sector_id
       FROM accounts WHERE id = $1 AND tenant_id = $2`,
      [req.params.id, tid(req)]
    )
    if (!row) return err(res, 404, 'Conta não encontrada')
    ok(res, row)
  } catch (e) { serverErr(res, e, 'getAccount') }
}

async function createAccount(req, res) {
  try {
    const { name, email, password, role, phone, avatar_url } = req.body
    if (!name) return err(res, 400, 'name obrigatório')
    const validRoles = ['owner','manager','supervisor','secretary','agent','viewer']
    if (role && !validRoles.includes(role)) return err(res, 400, 'role inválido')

    let hash = null
    if (password) hash = await bcrypt.hash(password, 10)

    const row = await queryOne(
      `INSERT INTO accounts (tenant_id, name, email, password_hash, role, phone, avatar_url)
       VALUES ($1,$2,$3,$4,$5,$6,$7) RETURNING id, name, email, role, phone, availability, active`,
      [tid(req), name, email||null, hash, role||'agent', phone||null, avatar_url||null]
    )
    ok(res, row)
  } catch (e) {
    if (e.code === '23505') return err(res, 409, 'E-mail já cadastrado neste tenant')
    serverErr(res, e, 'createAccount')
  }
}

async function updateAccount(req, res) {
  try {
    const { name, email, password, role, phone, availability, avatar_url, active,
            phone_connected, nw_team_id, nw_sector_id } = req.body
    const id = req.params.id

    const existing = await queryOne('SELECT id FROM accounts WHERE id=$1 AND tenant_id=$2', [id, tid(req)])
    if (!existing) return err(res, 404, 'Conta não encontrada')

    const sets = []
    const params = []

    if (name            !== undefined) { params.push(name);            sets.push(`name=$${params.length}`) }
    if (email           !== undefined) { params.push(email);           sets.push(`email=$${params.length}`) }
    if (role            !== undefined) { params.push(role);            sets.push(`role=$${params.length}`) }
    if (phone           !== undefined) { params.push(phone);           sets.push(`phone=$${params.length}`) }
    if (availability    !== undefined) { params.push(availability);    sets.push(`availability=$${params.length}`) }
    if (avatar_url      !== undefined) { params.push(avatar_url);      sets.push(`avatar_url=$${params.length}`) }
    if (active          !== undefined) { params.push(active);          sets.push(`active=$${params.length}`) }
    if (phone_connected !== undefined) { params.push(phone_connected); sets.push(`phone_connected=$${params.length}`) }
    if (nw_team_id      !== undefined) { params.push(nw_team_id);      sets.push(`nw_team_id=$${params.length}`) }
    if (nw_sector_id    !== undefined) { params.push(nw_sector_id);    sets.push(`nw_sector_id=$${params.length}`) }
    if (password) {
      const hash = await bcrypt.hash(password, 10)
      params.push(hash); sets.push(`password_hash=$${params.length}`)
    }

    if (sets.length === 0) return err(res, 400, 'Nenhum campo para atualizar')

    params.push(id, tid(req))
    const row = await queryOne(
      `UPDATE accounts SET ${sets.join(', ')} WHERE id=$${params.length-1} AND tenant_id=$${params.length}
       RETURNING id, name, email, role, phone, phone_connected, availability, active`,
      params
    )
    ok(res, row)
  } catch (e) {
    if (e.code === '23505') return err(res, 409, 'E-mail já cadastrado neste tenant')
    serverErr(res, e, 'updateAccount')
  }
}

async function deleteAccount(req, res) {
  try {
    const result = await execute(
      'DELETE FROM accounts WHERE id=$1 AND tenant_id=$2',
      [req.params.id, tid(req)]
    )
    if (result.rowCount === 0) return err(res, 404, 'Conta não encontrada')
    ok(res, { deleted: true })
  } catch (e) { serverErr(res, e, 'deleteAccount') }
}

// ─── SECTORS ────────────────────────────────────────────────────────────────

async function listSectors(req, res) {
  try {
    const rows = await query(
      `SELECT s.id, s.name, s.description, s.icon, s.color, s.sla_minutes,
              s.sort_order, s.active, s.created_at,
              COUNT(tm.id)::int AS member_count
       FROM sectors s
       LEFT JOIN team_members tm ON tm.sector_id = s.id
       WHERE s.tenant_id = $1
       GROUP BY s.id
       ORDER BY s.sort_order, s.name`,
      [tid(req)]
    )
    ok(res, rows)
  } catch (e) { serverErr(res, e, 'listSectors') }
}

async function getSector(req, res) {
  try {
    const sector = await queryOne(
      'SELECT * FROM sectors WHERE id=$1 AND tenant_id=$2',
      [req.params.id, tid(req)]
    )
    if (!sector) return err(res, 404, 'Setor não encontrado')

    const members = await query(
      `SELECT a.id, a.name, a.role, a.availability, a.phone_connected,
              tm.function, tm.is_primary, tm.on_duty, tm.notify_escalation, tm.notify_human_api
       FROM team_members tm
       JOIN accounts a ON a.id = tm.account_id
       WHERE tm.sector_id = $1`,
      [req.params.id]
    )
    ok(res, { ...sector, members })
  } catch (e) { serverErr(res, e, 'getSector') }
}

async function createSector(req, res) {
  try {
    const { name, description, icon, color, sla_minutes, sort_order } = req.body
    if (!name) return err(res, 400, 'name obrigatório')
    const row = await queryOne(
      `INSERT INTO sectors (tenant_id, name, description, icon, color, sla_minutes, sort_order)
       VALUES ($1,$2,$3,$4,$5,$6,$7) RETURNING *`,
      [tid(req), name, description||null, icon||'Briefcase', color||'#6366f1',
       sla_minutes||60, sort_order||0]
    )
    ok(res, row)
  } catch (e) { serverErr(res, e, 'createSector') }
}

async function updateSector(req, res) {
  try {
    const { name, description, icon, color, sla_minutes, sort_order, active } = req.body
    const id = req.params.id
    const existing = await queryOne('SELECT id FROM sectors WHERE id=$1 AND tenant_id=$2', [id, tid(req)])
    if (!existing) return err(res, 404, 'Setor não encontrado')

    const sets = []; const params = []
    if (name        !== undefined) { params.push(name);        sets.push(`name=$${params.length}`) }
    if (description !== undefined) { params.push(description); sets.push(`description=$${params.length}`) }
    if (icon        !== undefined) { params.push(icon);        sets.push(`icon=$${params.length}`) }
    if (color       !== undefined) { params.push(color);       sets.push(`color=$${params.length}`) }
    if (sla_minutes !== undefined) { params.push(sla_minutes); sets.push(`sla_minutes=$${params.length}`) }
    if (sort_order  !== undefined) { params.push(sort_order);  sets.push(`sort_order=$${params.length}`) }
    if (active      !== undefined) { params.push(active);      sets.push(`active=$${params.length}`) }
    if (sets.length === 0) return err(res, 400, 'Nenhum campo para atualizar')

    params.push(id, tid(req))
    const row = await queryOne(
      `UPDATE sectors SET ${sets.join(', ')} WHERE id=$${params.length-1} AND tenant_id=$${params.length} RETURNING *`,
      params
    )
    ok(res, row)
  } catch (e) { serverErr(res, e, 'updateSector') }
}

async function deleteSector(req, res) {
  try {
    const result = await execute('DELETE FROM sectors WHERE id=$1 AND tenant_id=$2', [req.params.id, tid(req)])
    if (result.rowCount === 0) return err(res, 404, 'Setor não encontrado')
    ok(res, { deleted: true })
  } catch (e) { serverErr(res, e, 'deleteSector') }
}

// ─── TEAM MEMBERS ────────────────────────────────────────────────────────────

async function listTeamMembers(req, res) {
  try {
    const { sector_id } = req.query
    let sql = `
      SELECT tm.id, tm.account_id, tm.sector_id, tm.function, tm.is_primary,
             tm.on_duty, tm.notify_escalation, tm.notify_human_api, tm.created_at,
             a.name AS account_name, a.email AS account_email, a.role AS account_role,
             a.availability, a.phone_connected,
             s.name AS sector_name, s.color AS sector_color, s.icon AS sector_icon
      FROM team_members tm
      JOIN accounts a ON a.id = tm.account_id
      JOIN sectors  s ON s.id = tm.sector_id
      WHERE a.tenant_id = $1
    `
    const params = [tid(req)]
    if (sector_id) { params.push(sector_id); sql += ` AND tm.sector_id = $${params.length}` }
    sql += ' ORDER BY s.name, a.name'
    const rows = await query(sql, params)
    ok(res, rows)
  } catch (e) { serverErr(res, e, 'listTeamMembers') }
}

async function addTeamMember(req, res) {
  try {
    const { account_id, sector_id, function: fn, is_primary, notify_escalation, notify_human_api } = req.body
    if (!account_id || !sector_id) return err(res, 400, 'account_id e sector_id obrigatórios')

    // verifica que a conta pertence ao tenant
    const acc = await queryOne('SELECT id FROM accounts WHERE id=$1 AND tenant_id=$2', [account_id, tid(req)])
    if (!acc) return err(res, 404, 'Conta não encontrada')
    const sec = await queryOne('SELECT id FROM sectors WHERE id=$1 AND tenant_id=$2', [sector_id, tid(req)])
    if (!sec) return err(res, 404, 'Setor não encontrado')

    const row = await queryOne(
      `INSERT INTO team_members (account_id, sector_id, function, is_primary, notify_escalation, notify_human_api)
       VALUES ($1,$2,$3,$4,$5,$6) RETURNING *`,
      [account_id, sector_id, fn||null,
       is_primary !== undefined ? is_primary : false,
       notify_escalation !== undefined ? notify_escalation : true,
       notify_human_api  !== undefined ? notify_human_api  : true]
    )
    ok(res, row)
  } catch (e) {
    if (e.code === '23505') return err(res, 409, 'Membro já vinculado a este setor')
    serverErr(res, e, 'addTeamMember')
  }
}

async function updateTeamMember(req, res) {
  try {
    const { function: fn, is_primary, on_duty, notify_escalation, notify_human_api } = req.body
    const id = req.params.id
    const sets = []; const params = []
    if (fn                !== undefined) { params.push(fn);                sets.push(`function=$${params.length}`) }
    if (is_primary        !== undefined) { params.push(is_primary);        sets.push(`is_primary=$${params.length}`) }
    if (on_duty           !== undefined) { params.push(on_duty);           sets.push(`on_duty=$${params.length}`) }
    if (notify_escalation !== undefined) { params.push(notify_escalation); sets.push(`notify_escalation=$${params.length}`) }
    if (notify_human_api  !== undefined) { params.push(notify_human_api);  sets.push(`notify_human_api=$${params.length}`) }
    if (sets.length === 0) return err(res, 400, 'Nenhum campo para atualizar')
    params.push(id)
    const row = await queryOne(`UPDATE team_members SET ${sets.join(', ')} WHERE id=$${params.length} RETURNING *`, params)
    if (!row) return err(res, 404, 'Membro não encontrado')
    ok(res, row)
  } catch (e) { serverErr(res, e, 'updateTeamMember') }
}

async function removeTeamMember(req, res) {
  try {
    const result = await execute('DELETE FROM team_members WHERE id=$1', [req.params.id])
    if (result.rowCount === 0) return err(res, 404, 'Membro não encontrado')
    ok(res, { deleted: true })
  } catch (e) { serverErr(res, e, 'removeTeamMember') }
}

// ─── SECTOR BRAIN NODES ─────────────────────────────────────────────────────

async function listSectorBrains(req, res) {
  try {
    const rows = await query(
      `SELECT * FROM sector_brain_nodes WHERE sector_id=$1 ORDER BY sort_order, id`,
      [req.params.sectorId]
    )
    ok(res, rows)
  } catch (e) { serverErr(res, e, 'listSectorBrains') }
}

async function createSectorBrain(req, res) {
  try {
    const { type, content, sort_order } = req.body
    if (!content) return err(res, 400, 'content obrigatório')
    const row = await queryOne(
      `INSERT INTO sector_brain_nodes (sector_id, type, content, sort_order)
       VALUES ($1,$2,$3,$4) RETURNING *`,
      [req.params.sectorId, type||'knowledge', content, sort_order||0]
    )
    ok(res, row)
  } catch (e) { serverErr(res, e, 'createSectorBrain') }
}

async function updateSectorBrain(req, res) {
  try {
    const { type, content, sort_order, active } = req.body
    const sets = []; const params = []
    if (type       !== undefined) { params.push(type);       sets.push(`type=$${params.length}`) }
    if (content    !== undefined) { params.push(content);    sets.push(`content=$${params.length}`) }
    if (sort_order !== undefined) { params.push(sort_order); sets.push(`sort_order=$${params.length}`) }
    if (active     !== undefined) { params.push(active);     sets.push(`active=$${params.length}`) }
    if (sets.length === 0) return err(res, 400, 'Nenhum campo para atualizar')
    params.push(req.params.id)
    const row = await queryOne(`UPDATE sector_brain_nodes SET ${sets.join(', ')} WHERE id=$${params.length} RETURNING *`, params)
    if (!row) return err(res, 404, 'Node não encontrado')
    ok(res, row)
  } catch (e) { serverErr(res, e, 'updateSectorBrain') }
}

async function deleteSectorBrain(req, res) {
  try {
    const result = await execute('DELETE FROM sector_brain_nodes WHERE id=$1', [req.params.id])
    if (result.rowCount === 0) return err(res, 404, 'Node não encontrado')
    ok(res, { deleted: true })
  } catch (e) { serverErr(res, e, 'deleteSectorBrain') }
}

// ─── PERFIL DO COLABORADOR LOGADO ────────────────────────────────────────────

async function me(req, res) {
  try {
    const accountId = req.teamAccount?.accountId || req.admin?.id
    const tenantId  = req.teamAccount?.tenantId  || req.tenantId || 1
    if (!accountId) return err(res, 401, 'Não autenticado')

    const row = await queryOne(`
      SELECT a.id, a.name, a.email, a.role, a.phone, a.phone_connected,
             a.availability, a.avatar_url, a.active, a.nw_team_id, a.nw_sector_id,
             COALESCE(
               json_agg(json_build_object(
                 'sector_id', s.id, 'sector_name', s.name,
                 'function', tm.function, 'is_primary', tm.is_primary, 'on_duty', tm.on_duty
               )) FILTER (WHERE tm.id IS NOT NULL), '[]'
             ) AS sectors
      FROM accounts a
      LEFT JOIN team_members tm ON tm.account_id = a.id
      LEFT JOIN sectors s ON s.id = tm.sector_id
      WHERE a.id = $1 AND a.tenant_id = $2
      GROUP BY a.id
    `, [accountId, tenantId])

    if (!row) return err(res, 404, 'Conta não encontrada')
    ok(res, row)
  } catch (e) { serverErr(res, e, 'me') }
}

// ─── INBOX INTERNA ───────────────────────────────────────────────────────────

/** Lista threads únicas com última mensagem + contador de não lidas */
async function listThreads(req, res) {
  try {
    // Segurança: colaborador só pode ver sua própria inbox.
    // Admin pode passar account_id na query para inspecionar qualquer conta.
    const isAdmin   = !!req.admin
    // queriedId pode ser NaN se não for passado — trata como null
    const queriedId = req.query.account_id ? parseInt(req.query.account_id) : null
    const ownId     = req.teamAccount?.accountId

    if (!isAdmin && queriedId && queriedId !== ownId) {
      return err(res, 403, 'Acesso negado: você só pode ver sua própria inbox')
    }

    // Colaborador sem account_id na query usa o próprio id do token
    const account_id = isAdmin ? (queriedId || null) : (queriedId || ownId)
    if (!account_id) return ok(res, [])

    const rows = await query(`
      SELECT DISTINCT ON (im.thread_id)
        im.thread_id,
        im.type,
        im.sector_id,
        s.name AS sector_name,
        im.content AS last_message,
        im.created_at AS last_at,
        im.ref_id,
        im.chat_id,
        COUNT(im2.id) FILTER (WHERE im2.read_at IS NULL AND im2.to_account = $2)::int AS unread
      FROM internal_messages im
      LEFT JOIN sectors s ON s.id = im.sector_id
      LEFT JOIN internal_messages im2 ON im2.thread_id = im.thread_id
      WHERE im.tenant_id = $1
        AND (im.to_account = $2 OR im.sector_id IN (
              SELECT sector_id FROM team_members WHERE account_id = $2
            ))
      GROUP BY im.thread_id, im.type, im.sector_id, s.name, im.content, im.created_at, im.ref_id, im.chat_id
      ORDER BY im.thread_id, im.created_at DESC
    `, [tid(req), account_id])
    ok(res, rows)
  } catch (e) { serverErr(res, e, 'listThreads') }
}

/** Lista mensagens de uma thread */
async function getThread(req, res) {
  try {
    const rows = await query(
      `SELECT im.*, a.name AS from_name, a.avatar_url AS from_avatar
       FROM internal_messages im
       LEFT JOIN accounts a ON a.id = im.from_account
       WHERE im.thread_id = $1 AND im.tenant_id = $2
       ORDER BY im.created_at`,
      [req.params.threadId, tid(req)]
    )
    ok(res, rows)
  } catch (e) { serverErr(res, e, 'getThread') }
}

/** Envia mensagem em uma thread (ou cria nova thread) */
async function postMessage(req, res) {
  try {
    const { thread_id, from_account, to_account, sector_id, type, content, ref_id } = req.body
    if (!content) return err(res, 400, 'content obrigatório')

    const threadId = thread_id || `t-${Date.now()}-${Math.random().toString(36).slice(2,8)}`
    const row = await queryOne(
      `INSERT INTO internal_messages (tenant_id, thread_id, from_account, to_account, sector_id, type, content, ref_id)
       VALUES ($1,$2,$3,$4,$5,$6,$7,$8) RETURNING *`,
      [tid(req), threadId, from_account||null, to_account||null, sector_id||null,
       type||'collaboration', content, ref_id||null]
    )
    ok(res, row)
  } catch (e) { serverErr(res, e, 'postMessage') }
}

/** Marca mensagens de uma thread como lidas */
async function markRead(req, res) {
  try {
    // Colaborador só pode marcar suas próprias mensagens como lidas
    const isAdmin   = !!req.admin
    const ownId     = req.teamAccount?.accountId
    const bodyId    = parseInt(req.body.account_id)
    const account_id = isAdmin ? bodyId : ownId

    if (!isAdmin && bodyId && bodyId !== ownId) {
      return err(res, 403, 'Acesso negado')
    }
    if (!account_id) return ok(res, { ok: true })

    await execute(
      `UPDATE internal_messages SET read_at = NOW()
       WHERE thread_id = $1 AND to_account = $2 AND read_at IS NULL`,
      [req.params.threadId, account_id]
    )
    ok(res, { ok: true })
  } catch (e) { serverErr(res, e, 'markRead') }
}

/** Conta não lidas de uma conta */
async function unreadCount(req, res) {
  try {
    const isAdmin   = !!req.admin
    const queriedId = parseInt(req.query.account_id)
    const ownId     = req.teamAccount?.accountId

    if (!isAdmin && queriedId && queriedId !== ownId) {
      return err(res, 403, 'Acesso negado')
    }
    const account_id = isAdmin ? queriedId : ownId
    if (!account_id) return ok(res, { count: 0 })

    const row = await queryOne(
      `SELECT COUNT(*)::int AS count FROM internal_messages
       WHERE tenant_id=$1 AND to_account=$2 AND read_at IS NULL`,
      [tid(req), account_id]
    )
    ok(res, row)
  } catch (e) { serverErr(res, e, 'unreadCount') }
}

// ─── EXPORTS ─────────────────────────────────────────────────────────────────

module.exports = {
  // perfil do colaborador logado
  me,
  // accounts
  listAccounts, getAccount, createAccount, updateAccount, deleteAccount,
  // sectors
  listSectors, getSector, createSector, updateSector, deleteSector,
  // team members
  listTeamMembers, addTeamMember, updateTeamMember, removeTeamMember,
  // sector brains
  listSectorBrains, createSectorBrain, updateSectorBrain, deleteSectorBrain,
  // inbox interna
  listThreads, getThread, postMessage, markRead, unreadCount,
}
