const express = require('express');
const multer = require('multer');
const { audit, now, one, run } = require('../db');
const { annualSchedule } = require('../depreciation');
const { requireCapability } = require('../middleware/auth');
const {
  addAssetPhoto,
  createAsset,
  deleteAsset,
  deleteAssetPhoto,
  hydrateAsset,
  listAssets,
  lookupAssetByCode,
  massUpdateAssets,
  updateAsset,
  updateAssetPhoto
} = require('../services/assets');
const { ruleSetForBook } = require('../services/ruleSets');

const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 16 * 1024 * 1024 } });
const router = express.Router();

router.get('/assets', (req, res) => {
  res.json({ assets: listAssets({ ...req.query, entity_id: req.companyId }) });
});

router.post('/assets', requireCapability('assets.edit'), (req, res) => {
  res.status(201).json({ asset: createAsset(req.body, req.user.id, req.companyId) });
});

router.get('/assets/lookup', (req, res) => {
  const code = String(req.query.code || '').trim();
  if (!code) return res.status(400).json({ error: 'Scan code is required' });
  const asset = lookupAssetByCode(code, req.companyId);
  if (!asset) return res.status(404).json({ error: `No asset matches "${code}"` });
  return res.json({ asset });
});

router.get('/assets/:id', (req, res) => {
  const asset = hydrateAsset(req.params.id);
  if (!asset || (req.companyId && asset.entity_id !== req.companyId)) return res.status(404).json({ error: 'Asset not found' });
  return res.json({ asset });
});

router.put('/assets/:id', requireCapability('assets.edit'), (req, res) => {
  const asset = updateAsset(req.params.id, req.body, req.user.id, req.companyId);
  if (!asset) return res.status(404).json({ error: 'Asset not found' });
  return res.json({ asset });
});

router.delete('/assets/:id', requireCapability('assets.delete'), (req, res) => {
  if (!deleteAsset(req.params.id, req.user.id, req.companyId)) return res.status(404).json({ error: 'Asset not found' });
  return res.status(204).end();
});

router.post('/assets/mass-update', requireCapability('assets.bulk'), (req, res) => {
  const ids = Array.isArray(req.body.ids) ? req.body.ids : [];
  const updated = massUpdateAssets(ids, req.body.changes || {}, req.user.id, req.companyId);
  if (!updated) return res.status(400).json({ error: 'Choose assets and editable fields' });
  return res.json({ updated });
});

router.get('/assets/:id/depreciation', (req, res) => {
  const asset = hydrateAsset(req.params.id);
  if (!asset || (req.companyId && asset.entity_id !== req.companyId)) return res.status(404).json({ error: 'Asset not found' });
  const startYear = Number(req.query.startYear || new Date().getFullYear());
  const endYear = Number(req.query.endYear || startYear + 5);
  const schedules = asset.books
    .filter((book) => book.active)
    .flatMap((book) => annualSchedule(asset, book, ruleSetForBook(book.book_type), { startYear, endYear }));
  res.json({ assetId: asset.asset_id, schedules });
});

router.post('/assets/:id/files', upload.single('file'), requireCapability('assets.edit'), (req, res) => {
  if (!req.file) return res.status(400).json({ error: 'File is required' });
  const result = run(
    'INSERT INTO asset_files (asset_id, file_name, mime_type, size, content_base64, uploaded_by, uploaded_at) VALUES (?, ?, ?, ?, ?, ?, ?)',
    [req.params.id, req.file.originalname, req.file.mimetype, req.file.size, req.file.buffer.toString('base64'), req.user.id, now()]
  );
  audit(req.user.id, 'upload_file', 'asset', req.params.id, null, { file: req.file.originalname });
  res.status(201).json({ file: one('SELECT id, file_name, mime_type, size, uploaded_at FROM asset_files WHERE id = ?', [result.lastInsertRowid]) });
});

router.get('/assets/:id/files/:fileId', (req, res) => {
  const file = one('SELECT * FROM asset_files WHERE id = ? AND asset_id = ?', [req.params.fileId, req.params.id]);
  if (!file) return res.status(404).json({ error: 'File not found' });
  res.setHeader('Content-Type', file.mime_type || 'application/octet-stream');
  res.setHeader('Content-Disposition', `attachment; filename="${file.file_name}"`);
  return res.send(Buffer.from(file.content_base64, 'base64'));
});

router.delete('/assets/:id/files/:fileId', requireCapability('assets.edit'), (req, res) => {
  const result = run('DELETE FROM asset_files WHERE id = ? AND asset_id = ?', [req.params.fileId, req.params.id]);
  if (!result.changes) return res.status(404).json({ error: 'File not found' });
  audit(req.user.id, 'delete', 'asset_file', req.params.fileId, null, { asset_id: req.params.id });
  return res.status(204).end();
});

// Identification photos (base64 data URLs, with optional captions)
router.post('/assets/:id/photos', requireCapability('assets.edit'), (req, res) => {
  const photo = addAssetPhoto(req.params.id, req.body, req.user.id);
  if (!photo) return res.status(404).json({ error: 'Asset not found' });
  return res.status(201).json({ photo });
});

router.put('/assets/:id/photos/:photoId', requireCapability('assets.edit'), (req, res) => {
  const photo = updateAssetPhoto(req.params.id, req.params.photoId, req.body, req.user.id);
  if (!photo) return res.status(404).json({ error: 'Photo not found' });
  return res.json({ photo });
});

router.delete('/assets/:id/photos/:photoId', requireCapability('assets.edit'), (req, res) => {
  if (!deleteAssetPhoto(req.params.id, req.params.photoId, req.user.id)) return res.status(404).json({ error: 'Photo not found' });
  return res.status(204).end();
});

router.post('/assets/:id/warranties', requireCapability('assets.edit'), (req, res) => {
  const b = req.body;
  const result = run(
    `INSERT INTO warranties (
      asset_id, provider, phone, start_date, expiration_date, warranty_limit,
      actual_usage, coverage_details, document_name, document_base64, created_at
    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
    [
      req.params.id, b.provider || null, b.phone || null, b.start_date || null, b.expiration_date || null,
      b.warranty_limit || null, b.actual_usage || null, b.coverage_details || null,
      b.document_name || null, b.document_base64 || null, now()
    ]
  );
  audit(req.user.id, 'create', 'warranty', result.lastInsertRowid, null, { ...b, document_base64: b.document_base64 ? '[stored]' : null });
  res.status(201).json({
    warranty: one(
      'SELECT id, provider, phone, start_date, expiration_date, warranty_limit, actual_usage, coverage_details, document_name, created_at FROM warranties WHERE id = ?',
      [result.lastInsertRowid]
    )
  });
});

router.delete('/assets/:id/warranties/:warrantyId', requireCapability('assets.edit'), (req, res) => {
  const result = run('DELETE FROM warranties WHERE id = ? AND asset_id = ?', [req.params.warrantyId, req.params.id]);
  if (!result.changes) return res.status(404).json({ error: 'Warranty not found' });
  audit(req.user.id, 'delete', 'warranty', req.params.warrantyId, null, { asset_id: req.params.id });
  return res.status(204).end();
});

router.post('/assets/:id/tasks', requireCapability('assets.edit'), (req, res) => {
  const created = now();
  const result = run(
    'INSERT INTO tasks (asset_id, title, type, status, due_date, assigned_to, notes, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
    [req.params.id, req.body.title, req.body.type || 'maintenance', req.body.status || 'open', req.body.due_date || null, req.body.assigned_to || null, req.body.notes || null, created, created]
  );
  audit(req.user.id, 'create', 'task', result.lastInsertRowid, null, req.body);
  res.status(201).json({ task: one('SELECT * FROM tasks WHERE id = ?', [result.lastInsertRowid]) });
});

router.put('/assets/:id/tasks/:taskId', requireCapability('assets.edit'), (req, res) => {
  const before = one('SELECT * FROM tasks WHERE id = ? AND asset_id = ?', [req.params.taskId, req.params.id]);
  if (!before) return res.status(404).json({ error: 'Task not found' });
  run(
    'UPDATE tasks SET title = ?, type = ?, status = ?, due_date = ?, notes = ?, updated_at = ? WHERE id = ?',
    [
      req.body.title ?? before.title,
      req.body.type ?? before.type,
      req.body.status ?? before.status,
      req.body.due_date ?? before.due_date,
      req.body.notes ?? before.notes,
      now(),
      req.params.taskId
    ]
  );
  audit(req.user.id, 'update', 'task', req.params.taskId, before, req.body);
  return res.json({ task: one('SELECT * FROM tasks WHERE id = ?', [req.params.taskId]) });
});

router.delete('/assets/:id/tasks/:taskId', requireCapability('assets.edit'), (req, res) => {
  const result = run('DELETE FROM tasks WHERE id = ? AND asset_id = ?', [req.params.taskId, req.params.id]);
  if (!result.changes) return res.status(404).json({ error: 'Task not found' });
  audit(req.user.id, 'delete', 'task', req.params.taskId, null, { asset_id: req.params.id });
  return res.status(204).end();
});

router.post('/assets/:id/notes', requireCapability('assets.edit'), (req, res) => {
  if (!req.body.body) return res.status(400).json({ error: 'Note body is required' });
  const result = run(
    'INSERT INTO asset_notes (asset_id, body, created_by, created_at) VALUES (?, ?, ?, ?)',
    [req.params.id, req.body.body, req.user.id, now()]
  );
  audit(req.user.id, 'create', 'asset_note', result.lastInsertRowid, null, { asset_id: req.params.id });
  res.status(201).json({
    note: one(
      'SELECT n.id, n.body, n.created_at, u.name AS author FROM asset_notes n LEFT JOIN users u ON u.id = n.created_by WHERE n.id = ?',
      [result.lastInsertRowid]
    )
  });
});

router.delete('/assets/:id/notes/:noteId', requireCapability('assets.edit'), (req, res) => {
  const result = run('DELETE FROM asset_notes WHERE id = ? AND asset_id = ?', [req.params.noteId, req.params.id]);
  if (!result.changes) return res.status(404).json({ error: 'Note not found' });
  audit(req.user.id, 'delete', 'asset_note', req.params.noteId, null, { asset_id: req.params.id });
  return res.status(204).end();
});

module.exports = router;
