/**
 * Branch Controller
 * API endpoints para gestión de sucursales
 *
 * @module Branches
 * @prefix /api/v1/branches
 */

import { Router, Request, Response, NextFunction } from 'express';
import {
  BranchService,
  CreateBranchDto,
  UpdateBranchDto,
  ServiceContext,
} from '../services/branch.service';

const router = Router();
const branchService = new BranchService();

/**
 * Helper to extract ServiceContext from request
 */
function getContext(req: Request): ServiceContext {
  return {
    tenantId: req.headers['x-tenant-id'] as string,
    userId: (req as any).user?.id,
  };
}

/**
 * GET /api/v1/branches
 * Lista todas las sucursales del tenant
 */
router.get('/', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { branchType, isActive, city, state, parentId, page, limit } = req.query;

    const result = await branchService.findAll(
      getContext(req),
      {
        branchType: branchType as any,
        isActive: isActive === 'true' ? true : isActive === 'false' ? false : undefined,
        city: city as string,
        state: state as string,
        parentId: parentId as string,
      },
      {
        page: page ? parseInt(page as string) : undefined,
        limit: limit ? parseInt(limit as string) : undefined,
      }
    );

    return res.json({
      success: true,
      ...result,
    });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/branches/statistics
 * Estadísticas de sucursales
 */
router.get('/statistics', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const stats = await branchService.getStatistics(getContext(req));
    return res.json({ success: true, data: stats });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/branches/hierarchy
 * Obtiene la jerarquía completa de sucursales
 */
router.get('/hierarchy', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const hierarchy = await branchService.getHierarchy(getContext(req));
    return res.json({ success: true, data: hierarchy });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/branches/roots
 * Obtiene las sucursales raíz (sin padre)
 */
router.get('/roots', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const roots = await branchService.findRootBranches(getContext(req));
    return res.json({ success: true, data: roots, count: roots.length });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/branches/main
 * Obtiene la sucursal principal/matriz
 */
router.get('/main', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const main = await branchService.findMainBranch(getContext(req));
    if (!main) {
      return res.status(404).json({ error: 'No hay sucursal principal configurada' });
    }

    return res.json({ success: true, data: main });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/branches/nearby
 * Busca sucursales cercanas a una ubicación
 */
router.get('/nearby', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const { lat, lng, radius } = req.query;

    if (!lat || !lng) {
      return res.status(400).json({ error: 'lat y lng son requeridos' });
    }

    const branches = await branchService.findByLocation(
      getContext(req),
      parseFloat(lat as string),
      parseFloat(lng as string),
      radius ? parseFloat(radius as string) : undefined
    );

    return res.json({ success: true, data: branches, count: branches.length });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/branches/:id
 * Obtiene una sucursal por ID
 */
router.get('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const branch = await branchService.findById(getContext(req), req.params.id);
    if (!branch) {
      return res.status(404).json({ error: 'Sucursal no encontrada' });
    }

    return res.json({ success: true, data: branch });
  } catch (error) {
    return next(error);
  }
});

/**
 * GET /api/v1/branches/:id/children
 * Obtiene las sucursales hijas de una sucursal
 */
router.get('/:id/children', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const children = await branchService.findChildren(getContext(req), req.params.id);
    return res.json({ success: true, data: children, count: children.length });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/branches
 * Crea una nueva sucursal
 */
router.post('/', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const data: CreateBranchDto = req.body;

    // Validate required fields
    if (!data.code || !data.name) {
      return res.status(400).json({ error: 'code y name son requeridos' });
    }

    // Check if code already exists
    const existing = await branchService.findByCode(getContext(req), data.code);
    if (existing) {
      return res.status(409).json({ error: 'Ya existe una sucursal con ese código' });
    }

    const branch = await branchService.create(getContext(req), data);
    return res.status(201).json({ success: true, data: branch });
  } catch (error) {
    return next(error);
  }
});

/**
 * PATCH /api/v1/branches/:id
 * Actualiza una sucursal
 */
router.patch('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const data: UpdateBranchDto = req.body;
    const branch = await branchService.update(getContext(req), req.params.id, data);

    if (!branch) {
      return res.status(404).json({ error: 'Sucursal no encontrada' });
    }

    return res.json({ success: true, data: branch });
  } catch (error) {
    return next(error);
  }
});

/**
 * POST /api/v1/branches/:id/set-main
 * Establece una sucursal como principal/matriz
 */
router.post('/:id/set-main', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const branch = await branchService.setAsMain(getContext(req), req.params.id);
    if (!branch) {
      return res.status(404).json({ error: 'Sucursal no encontrada' });
    }

    return res.json({ success: true, data: branch, message: 'Sucursal establecida como principal' });
  } catch (error) {
    return next(error);
  }
});

/**
 * DELETE /api/v1/branches/:id
 * Elimina una sucursal (soft delete)
 */
router.delete('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'X-Tenant-Id header required' });
    }

    const deleted = await branchService.delete(getContext(req), req.params.id);
    if (!deleted) {
      return res.status(404).json({ error: 'Sucursal no encontrada' });
    }

    return res.json({ success: true, message: 'Sucursal eliminada' });
  } catch (error: any) {
    if (error.message?.includes('children')) {
      return res.status(400).json({ error: error.message });
    }
    return next(error);
  }
});

export default router;
