import { Router } from 'express'
import { z } from 'zod'
import multer from 'multer'
import { prisma } from '../lib/prisma'
import { uploadImage } from '../lib/storage'
import { requireCompanyAuth } from '../middleware/requireCompanyAuth'
import { requireTenant } from '../middleware/requireTenant'
import { requireSubscription } from '../middleware/requireSubscription'

const router = Router()
const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 10 * 1024 * 1024 } })
router.use(requireCompanyAuth, requireTenant, requireSubscription)

const companySchema = z.object({
  name: z.string().min(1).optional(),
  email: z.string().email().optional(),
  phone: z.string().optional(),
  address: z.record(z.unknown()).optional(),
})

const brandSchema = z.object({
  displayName: z.string().min(1).optional(),
  tagline: z.string().optional(),
  primaryColor: z.string().optional(),
  accentColor: z.string().optional(),
  publicEmail: z.string().email().optional(),
  publicPhone: z.string().optional(),
  publicAddress: z.string().optional(),
  publicCity: z.string().optional(),
  publicCountry: z.string().optional(),
  websiteUrl: z.string().url().optional(),
  whatsappNumber: z.string().optional(),
  defaultLocale: z.string().optional(),
  defaultCurrency: z.enum(['MAD', 'USD', 'EUR']).optional(),
  amanpayMerchantId: z.string().optional(),
  amanpaySecretKey: z.string().optional(),
  paypalEmail: z.string().email().optional(),
  paypalMerchantId: z.string().optional(),
  isListedOnMarketplace: z.boolean().optional(),
  homePageConfig: z.object({
    heroTitle: z.union([z.string(), z.null()]).optional(),
    heroDescription: z.union([z.string(), z.null()]).optional(),
    viewOffersLabel: z.union([z.string(), z.null()]).optional(),
    viewPricingLabel: z.union([z.string(), z.null()]).optional(),
    contactCompanyLabel: z.union([z.string(), z.null()]).optional(),
    activeOffersTitle: z.union([z.string(), z.null()]).optional(),
    seeAllOffersLabel: z.union([z.string(), z.null()]).optional(),
    noActiveOffersLabel: z.union([z.string(), z.null()]).optional(),
    publishedVehiclesTitle: z.union([z.string(), z.null()]).optional(),
    viewVehicleLabel: z.union([z.string(), z.null()]).optional(),
    pricingEyebrow: z.union([z.string(), z.null()]).optional(),
    pricingTitle: z.union([z.string(), z.null()]).optional(),
    pricingDescription: z.union([z.string(), z.null()]).optional(),
    showOffers: z.boolean().optional(),
    showVehicles: z.boolean().optional(),
    showPricing: z.boolean().optional(),
    layout: z.object({
      items: z.array(z.object({
        id: z.string().min(1),
        type: z.enum(['hero', 'offers', 'vehicles', 'pricing']),
        x: z.number().int().min(1),
        y: z.number().int().min(1),
        w: z.number().int().min(1),
        h: z.number().int().min(1),
      })),
    }).optional(),
  }).optional(),
  menuConfig: z.object({
    aboutLabel: z.union([z.string(), z.null()]).optional(),
    vehiclesLabel: z.union([z.string(), z.null()]).optional(),
    offersLabel: z.union([z.string(), z.null()]).optional(),
    pricingLabel: z.union([z.string(), z.null()]).optional(),
    blogLabel: z.union([z.string(), z.null()]).optional(),
    contactLabel: z.union([z.string(), z.null()]).optional(),
    bookCarLabel: z.union([z.string(), z.null()]).optional(),
    siteNavigationLabel: z.union([z.string(), z.null()]).optional(),
    showAbout: z.boolean().optional(),
    showVehicles: z.boolean().optional(),
    showOffers: z.boolean().optional(),
    showPricing: z.boolean().optional(),
    showBlog: z.boolean().optional(),
    showContact: z.boolean().optional(),
    pageSections: z.object({
      home: z.object({
        hero: z.boolean().optional(),
        offers: z.boolean().optional(),
        vehicles: z.boolean().optional(),
        pricing: z.boolean().optional(),
      }).optional(),
      about: z.object({
        hero: z.boolean().optional(),
        highlights: z.boolean().optional(),
        details: z.boolean().optional(),
      }).optional(),
      offers: z.object({
        header: z.boolean().optional(),
        grid: z.boolean().optional(),
      }).optional(),
      pricing: z.object({
        hero: z.boolean().optional(),
        plans: z.boolean().optional(),
        payments: z.boolean().optional(),
        faq: z.boolean().optional(),
      }).optional(),
      vehicles: z.object({
        header: z.boolean().optional(),
        filters: z.boolean().optional(),
        grid: z.boolean().optional(),
      }).optional(),
      vehicleDetail: z.object({
        gallery: z.boolean().optional(),
        summary: z.boolean().optional(),
      }).optional(),
      blog: z.object({
        hero: z.boolean().optional(),
        posts: z.boolean().optional(),
      }).optional(),
      contact: z.object({
        content: z.boolean().optional(),
      }).optional(),
      booking: z.object({
        content: z.boolean().optional(),
      }).optional(),
      bookingConfirmation: z.object({
        hero: z.boolean().optional(),
        summary: z.boolean().optional(),
        actions: z.boolean().optional(),
      }).optional(),
    }).optional(),
  }).optional(),
})

const contractSettingsSchema = z.object({
  legalName: z.string().optional(),
  registrationNumber: z.string().optional(),
  taxId: z.string().optional(),
  terms: z.string().optional(),
  fuelPolicy: z.string().optional(),
  depositPolicy: z.string().optional(),
  lateFeePolicy: z.string().optional(),
  damagePolicy: z.string().optional(),
  contractFooterNote: z.string().optional(),
  invoiceFooterNote: z.string().optional(),
  signatureRequired: z.boolean().optional(),
  showTax: z.boolean().optional(),
  taxRate: z.number().optional(),
  taxLabel: z.string().optional(),
  fuelPolicyType: z.enum(['FULL_TO_FULL', 'FULL_TO_EMPTY', 'SAME_TO_SAME', 'PREPAID', 'FREE']).optional(),
  fuelPolicyNote: z.string().optional(),
  fuelChargePerLiter: z.number().int().optional(),
  fuelShortfallFee: z.number().int().optional(),
  lateFeePerHour: z.number().int().optional(),
  additionalDriverCharge: z.enum(['FREE', 'PER_DAY', 'FLAT']).optional(),
  additionalDriverDailyRate: z.number().int().optional(),
  additionalDriverFlatRate: z.number().int().optional(),
})

const insurancePolicySchema = z.object({
  name: z.string().min(1),
  description: z.string().optional(),
  type: z.enum(['CDW', 'SCDW', 'THEFT', 'THIRD_PARTY', 'FULL', 'BASIC', 'ROADSIDE', 'PERSONAL', 'CUSTOM']),
  chargeType: z.enum(['PER_DAY', 'PER_RENTAL', 'PERCENTAGE_OF_RENTAL']),
  chargeValue: z.number().int().min(0),
  isRequired: z.boolean().default(false),
  isActive: z.boolean().default(true),
  sortOrder: z.number().int().default(0),
})

const pricingRuleSchema = z.object({
  name: z.string().min(1),
  type: z.enum(['SURCHARGE', 'DISCOUNT']),
  condition: z.enum(['AGE_LESS_THAN', 'AGE_GREATER_THAN', 'LICENSE_YEARS_LESS_THAN', 'LICENSE_YEARS_GREATER_THAN']),
  conditionValue: z.number().int(),
  adjustmentType: z.enum(['PERCENTAGE', 'FLAT_PER_DAY', 'FLAT_TOTAL']),
  adjustmentValue: z.number().int(),
  isActive: z.boolean().default(true),
  description: z.string().optional(),
})

const accountingSettingsSchema = z.object({
  reportingPeriod: z.enum(['WEEKLY', 'MONTHLY', 'QUARTERLY', 'ANNUAL']).optional(),
  fiscalYearStart: z.number().int().min(1).max(12).optional(),
  currency: z.enum(['MAD', 'USD', 'EUR']).optional(),
  accountantEmail: z.string().email().optional(),
  accountantName: z.string().optional(),
  autoSendReport: z.boolean().optional(),
  reportFormat: z.enum(['PDF', 'CSV', 'BOTH']).optional(),
})

function buildPaymentMethodsEnabled(input: {
  amanpayMerchantId?: string | null
  amanpaySecretKey?: string | null
  paypalEmail?: string | null
}) {
  const methods: Array<'AMANPAY' | 'PAYPAL'> = []
  if (input.amanpayMerchantId && input.amanpaySecretKey) methods.push('AMANPAY')
  if (input.paypalEmail) methods.push('PAYPAL')
  return methods
}

router.get('/me', async (req, res, next) => {
  try {
    const company = await prisma.company.findUniqueOrThrow({
      where: { id: req.companyId },
      include: {
        brand: true,
        subscription: true,
        _count: { select: { vehicles: true, customers: true, reservations: true } },
      },
    })
    res.json({ data: company })
  } catch (err) { next(err) }
})

router.patch('/me', async (req, res, next) => {
  try {
    const body = companySchema.parse(req.body)
    const company = await prisma.company.update({
      where: { id: req.companyId },
      data: body as any,
    })
    res.json({ data: company })
  } catch (err) { next(err) }
})

router.get('/me/brand', async (req, res, next) => {
  try {
    const brand = await prisma.brandSettings.findUnique({
      where: { companyId: req.companyId },
    })
    res.json({ data: brand })
  } catch (err) { next(err) }
})

router.patch('/me/brand', async (req, res, next) => {
  try {
    const body = brandSchema.parse(req.body)
    const current = await prisma.brandSettings.findUnique({ where: { companyId: req.companyId } })
    const paymentMethodsEnabled = buildPaymentMethodsEnabled({
      amanpayMerchantId: body.amanpayMerchantId ?? current?.amanpayMerchantId,
      amanpaySecretKey: body.amanpaySecretKey ?? current?.amanpaySecretKey,
      paypalEmail: body.paypalEmail ?? current?.paypalEmail,
    })
    const brand = await prisma.brandSettings.upsert({
      where: { companyId: req.companyId },
      update: { ...body, paymentMethodsEnabled },
      create: {
        companyId: req.companyId,
        displayName: body.displayName ?? req.company.name,
        subdomain: req.company.slug,
        paymentMethodsEnabled,
        ...body,
      },
    })
    res.json({ data: brand })
  } catch (err) { next(err) }
})

router.post('/me/brand/logo', upload.single('file'), async (req, res, next) => {
  try {
    if (!req.file) {
      return res.status(400).json({ error: 'missing_file', message: 'A logo file is required', statusCode: 400 })
    }
    const url = await uploadImage(req.file.buffer, `companies/${req.companyId}/brand`, 'logo')
    const brand = await prisma.brandSettings.upsert({
      where: { companyId: req.companyId },
      update: { logoUrl: url },
      create: {
        companyId: req.companyId,
        displayName: req.company.name,
        subdomain: req.company.slug,
        logoUrl: url,
      },
    })
    res.json({ data: brand })
  } catch (err) { next(err) }
})

router.post('/me/brand/hero', upload.single('file'), async (req, res, next) => {
  try {
    if (!req.file) {
      return res.status(400).json({ error: 'missing_file', message: 'A hero image file is required', statusCode: 400 })
    }
    const url = await uploadImage(req.file.buffer, `companies/${req.companyId}/brand`, 'hero')
    const brand = await prisma.brandSettings.upsert({
      where: { companyId: req.companyId },
      update: { heroImageUrl: url },
      create: {
        companyId: req.companyId,
        displayName: req.company.name,
        subdomain: req.company.slug,
        heroImageUrl: url,
      },
    })
    res.json({ data: brand })
  } catch (err) { next(err) }
})

router.post('/me/brand/subdomain/check', async (req, res, next) => {
  try {
    const { subdomain } = z.object({ subdomain: z.string().min(3) }).parse(req.body)
    const existing = await prisma.brandSettings.findFirst({
      where: { subdomain, companyId: { not: req.companyId } },
    })
    res.json({ data: { available: !existing } })
  } catch (err) { next(err) }
})

router.post('/me/brand/custom-domain', async (req, res, next) => {
  try {
    const { customDomain } = z.object({ customDomain: z.string().min(3) }).parse(req.body)
    const normalized = customDomain.toLowerCase().trim()
    const existing = await prisma.brandSettings.findFirst({
      where: { customDomain: normalized, companyId: { not: req.companyId } },
    })
    if (existing) {
      return res.status(409).json({ error: 'domain_taken', message: 'This custom domain is already in use', statusCode: 409 })
    }
    const brand = await prisma.brandSettings.upsert({
      where: { companyId: req.companyId },
      update: {
        customDomain: normalized,
        customDomainVerified: false,
        customDomainAddedAt: new Date(),
      },
      create: {
        companyId: req.companyId,
        displayName: req.company.name,
        subdomain: req.company.slug,
        customDomain: normalized,
        customDomainVerified: false,
        customDomainAddedAt: new Date(),
      },
    })
    res.json({ data: brand })
  } catch (err) { next(err) }
})

router.get('/me/brand/custom-domain/status', async (req, res, next) => {
  try {
    const brand = await prisma.brandSettings.findUnique({ where: { companyId: req.companyId } })
    const customDomain = brand?.customDomain ?? null
    res.json({
      data: {
        customDomain,
        verified: brand?.customDomainVerified ?? false,
        status: customDomain ? (brand?.customDomainVerified ? 'verified' : 'pending_dns') : 'not_configured',
        dnsTarget: process.env.NEXT_PUBLIC_CUSTOM_DOMAIN_TARGET ?? 'cname.vercel-dns.com',
      },
    })
  } catch (err) { next(err) }
})

router.delete('/me/brand/custom-domain', async (req, res, next) => {
  try {
    const brand = await prisma.brandSettings.updateMany({
      where: { companyId: req.companyId },
      data: { customDomain: null, customDomainVerified: false, customDomainAddedAt: null },
    })
    res.json({ data: { success: brand.count > 0 } })
  } catch (err) { next(err) }
})

router.get('/me/contract-settings', async (req, res, next) => {
  try {
    const settings = await prisma.contractSettings.findUnique({ where: { companyId: req.companyId } })
    res.json({ data: settings })
  } catch (err) { next(err) }
})

router.patch('/me/contract-settings', async (req, res, next) => {
  try {
    const body = contractSettingsSchema.parse(req.body)
    const settings = await prisma.contractSettings.upsert({
      where: { companyId: req.companyId },
      update: body,
      create: { companyId: req.companyId, ...body },
    })
    res.json({ data: settings })
  } catch (err) { next(err) }
})

router.get('/me/insurance-policies', async (req, res, next) => {
  try {
    const policies = await prisma.insurancePolicy.findMany({
      where: { companyId: req.companyId },
      orderBy: [{ isRequired: 'desc' }, { sortOrder: 'asc' }, { name: 'asc' }],
    })
    res.json({ data: policies })
  } catch (err) { next(err) }
})

router.post('/me/insurance-policies', async (req, res, next) => {
  try {
    const body = insurancePolicySchema.parse(req.body)
    const policy = await prisma.insurancePolicy.create({ data: { companyId: req.companyId, ...body } })
    res.status(201).json({ data: policy })
  } catch (err) { next(err) }
})

router.patch('/me/insurance-policies/:id', async (req, res, next) => {
  try {
    const body = insurancePolicySchema.partial().parse(req.body)
    const policy = await prisma.insurancePolicy.updateMany({
      where: { id: req.params.id, companyId: req.companyId },
      data: body,
    })
    if (policy.count === 0) return res.status(404).json({ error: 'not_found', message: 'Insurance policy not found', statusCode: 404 })
    const updated = await prisma.insurancePolicy.findUniqueOrThrow({ where: { id: req.params.id } })
    res.json({ data: updated })
  } catch (err) { next(err) }
})

router.delete('/me/insurance-policies/:id', async (req, res, next) => {
  try {
    const deleted = await prisma.insurancePolicy.deleteMany({ where: { id: req.params.id, companyId: req.companyId } })
    if (deleted.count === 0) return res.status(404).json({ error: 'not_found', message: 'Insurance policy not found', statusCode: 404 })
    res.json({ data: { success: true } })
  } catch (err) { next(err) }
})

router.get('/me/pricing-rules', async (req, res, next) => {
  try {
    const rules = await prisma.pricingRule.findMany({
      where: { companyId: req.companyId },
      orderBy: [{ isActive: 'desc' }, { createdAt: 'asc' }],
    })
    res.json({ data: rules })
  } catch (err) { next(err) }
})

router.post('/me/pricing-rules', async (req, res, next) => {
  try {
    const body = pricingRuleSchema.parse(req.body)
    const rule = await prisma.pricingRule.create({ data: { companyId: req.companyId, ...body } })
    res.status(201).json({ data: rule })
  } catch (err) { next(err) }
})

router.patch('/me/pricing-rules/:id', async (req, res, next) => {
  try {
    const body = pricingRuleSchema.partial().parse(req.body)
    const updated = await prisma.pricingRule.updateMany({
      where: { id: req.params.id, companyId: req.companyId },
      data: body,
    })
    if (updated.count === 0) return res.status(404).json({ error: 'not_found', message: 'Pricing rule not found', statusCode: 404 })
    const rule = await prisma.pricingRule.findUniqueOrThrow({ where: { id: req.params.id } })
    res.json({ data: rule })
  } catch (err) { next(err) }
})

router.delete('/me/pricing-rules/:id', async (req, res, next) => {
  try {
    const deleted = await prisma.pricingRule.deleteMany({ where: { id: req.params.id, companyId: req.companyId } })
    if (deleted.count === 0) return res.status(404).json({ error: 'not_found', message: 'Pricing rule not found', statusCode: 404 })
    res.json({ data: { success: true } })
  } catch (err) { next(err) }
})

router.get('/me/accounting-settings', async (req, res, next) => {
  try {
    const settings = await prisma.accountingSettings.findUnique({ where: { companyId: req.companyId } })
    res.json({ data: settings })
  } catch (err) { next(err) }
})

router.patch('/me/accounting-settings', async (req, res, next) => {
  try {
    const body = accountingSettingsSchema.parse(req.body)
    const settings = await prisma.accountingSettings.upsert({
      where: { companyId: req.companyId },
      update: body,
      create: { companyId: req.companyId, ...body },
    })
    res.json({ data: settings })
  } catch (err) { next(err) }
})

router.get('/me/api-key', async (req, res, next) => {
  try {
    const company = await prisma.company.findUniqueOrThrow({
      where: { id: req.companyId },
      select: { apiKey: true },
    })
    res.json({ data: company })
  } catch (err) { next(err) }
})

router.post('/me/api-key/regenerate', async (req, res, next) => {
  try {
    const company = await prisma.company.update({
      where: { id: req.companyId },
      data: { apiKey: `api_${Math.random().toString(36).slice(2)}${Date.now()}` },
      select: { apiKey: true },
    })
    res.json({ data: company })
  } catch (err) { next(err) }
})

export default router
