import { Notify } from 'quasar'
import { createJob } from 'src/api/dispatch'
import { getDoc, createDoc } from 'src/api/erp'
import { HUB_URL } from 'src/data/wizard-constants'

export function useWizardPublish ({ props, emit, state }) {
  const {
    publishing, wizardSteps, orderItems, orderMode,
    contractNotes, requireAcceptance, acceptanceMethod,
    clientPhone, clientEmail,
    publishedDocName, publishedDocType, publishedDone,
    pendingAcceptance, acceptanceLinkUrl, acceptanceLinkSent,
    acceptanceSentVia, publishedJobCount,
    sendTo, sendChannel,
    publishedContractName,
    installFee, installRegular,
  } = state

  async function resolveAddress () {
    try {
      const locName = props.issue?.service_location || props.customer?.service_location
      if (locName) {
        const loc = await getDoc('Service Location', locName)
        return [loc.address_line, loc.city, loc.postal_code].filter(Boolean).join(', ')
      }
    } catch {}
    // Repli : adresse qualifiée par le wizard soumission (prospect sans Service Location encore) — le prix dépend de l'adresse.
    const qa = props.customer?.qualified_address
    return (qa && qa.address) || ''
  }

  async function publish () {
    if (publishing.value) return
    publishing.value = true

    try {
      const address = await resolveAddress()
      const customer = props.issue?.customer || props.customer?.name || ''
      const serviceLocation = props.issue?.service_location || props.customer?.service_location || ''
      const today = new Date().toISOString().split('T')[0]
      const onetimeItems = orderItems.value.filter(i => i.billing === 'onetime' && i.item_name)
      const recurringItems = orderItems.value.filter(i => i.billing === 'recurring' && i.item_name)
      let orderDocName = ''
      let orderDocType = ''
      const isQuotation = orderMode.value === 'quotation'
      const needsAcceptance = requireAcceptance.value && isQuotation
      const hasPhone = !!clientPhone.value
      const hasEmail = !!clientEmail.value

      const qa = props.customer?.qualified_address || null
      const wizardContext = {
        issue: props.issue?.name || '',
        customer,
        address,
        service_location: serviceLocation,
        // Adresse qualifiée + zone tarifaire (le prix dépend de l'adresse) — portées sur le devis même sans Service Location.
        ...(qa ? { zone_tarifaire: qa.zone ?? null, latitude: qa.lat ?? null, longitude: qa.lon ?? null, fiber_available: !!qa.fiber } : {}),
      }

      // Step extras — each wizardStep with extra_fee > 0 becomes a one-time
      // FEE-EXTRA line carrying the step subject so the agent can see what
      // the charge covered on the invoice.
      const stepExtraItems = wizardSteps.value
        .filter(s => Number(s.extra_fee) > 0)
        .map(s => {
          const label = (s.extra_label || '').trim() || 'Extra'
          const subject = s.subject || 'étape'
          return {
            item_name: `${label} — ${subject}`,
            item_code: 'FEE-EXTRA',
            qty: 1,
            rate: Number(s.extra_fee),
            description: `${label} sur l'étape « ${subject} »`,
            applies_to_item: '',
          }
        })

      // Create financial document
      if (orderItems.value.some(i => i.item_name) || stepExtraItems.length) {
        const allItems = [...onetimeItems, ...recurringItems].map(i => ({
          item_name: i.item_name,
          item_code: i.item_code || i.item_name,
          qty: i.qty,
          rate: i.rate,
          description: i.billing === 'recurring'
            ? `${i.item_name} — ${i.rate}$/mois × ${i.contract_months || 12} mois`
            : i.item_name,
          // Per-line rebate binding — consumed by the invoice Jinja to net the
          // rebate into its parent line for customer-facing docs. Empty for
          // non-rebate lines; extra fields are ignored by Frappe if unused.
          applies_to_item: i.applies_to_item || '',
        })).concat(stepExtraItems)

        const baseDoc = {
          customer,
          company: 'TARGO',
          currency: 'CAD',
          selling_price_list: 'Standard Selling',
          items: allItems,
          tc_name: contractNotes.value ? '' : undefined,
          terms: contractNotes.value || undefined,
        }

        try {
          if (isQuotation) {
            const quotPayload = {
              ...baseDoc,
              quotation_to: 'Customer',
              party_name: customer,
              valid_till: new Date(Date.now() + 30 * 86400000).toISOString().split('T')[0],
            }
            if (needsAcceptance) {
              quotPayload.wizard_steps = JSON.stringify(wizardSteps.value.map((s, i) => ({
                subject: s.subject,
                job_type: s.job_type || 'Autre',
                priority: s.priority || 'medium',
                duration_h: s.duration_h || 1,
                assigned_group: s.assigned_group || '',
                depends_on_step: s.depends_on_step,
                scheduled_date: s.scheduled_date || '',
                on_open_webhook: s.on_open_webhook || '',
                on_close_webhook: s.on_close_webhook || '',
                step_order: i + 1,
              })))
              quotPayload.wizard_context = JSON.stringify(wizardContext)
            }
            const quot = await createDoc('Quotation', quotPayload)
            orderDocName = quot.name
            orderDocType = 'Quotation'
          } else if (orderMode.value === 'prepaid') {
            const inv = await createDoc('Sales Invoice', {
              ...baseDoc, posting_date: today, due_date: today, is_pos: 0,
            })
            orderDocName = inv.name
            orderDocType = 'Sales Invoice'
          } else {
            const so = await createDoc('Sales Order', {
              ...baseDoc, transaction_date: today, delivery_date: today,
            })
            orderDocName = so.name
            orderDocType = 'Sales Order'
          }
        } catch (e) {
          // Surface the failure loudly — the rep needs to know why the
          // Quotation didn't land (commonly missing ERPNext Items like
          // TIER-G150, TV-MIX5, TEL-ILL). Service Contract creation below
          // still proceeds so the rep has *something* to retrieve.
          console.warn('[ProjectWizard] Order doc creation failed:', e.message)
          Notify.create({
            type: 'negative',
            message: 'Soumission non créée',
            caption: e.message?.slice(0, 180) || 'Erreur ERPNext',
            timeout: 8000,
            position: 'top',
            actions: [{ label: 'OK', color: 'white' }],
          })
        }

        // Create Subscriptions for recurring items (unless deferred)
        if (!needsAcceptance) {
          for (const item of recurringItems) {
            try {
              let planName = null
              try {
                const plans = await createDoc('Subscription Plan', {
                  plan_name: item.item_name,
                  item: item.item_code || item.item_name,
                  currency: 'CAD',
                  price_determination: 'Fixed Rate',
                  cost: item.rate,
                  billing_interval: item.billing_interval || 'Month',
                  billing_interval_count: 1,
                })
                planName = plans.name
              } catch {
                try {
                  const existing = await getDoc('Subscription Plan', item.item_code || item.item_name)
                  planName = existing.name
                } catch {}
              }

              await createDoc('Subscription', {
                party_type: 'Customer',
                party: customer,
                company: 'TARGO',
                status: 'Active',
                start_date: today,
                generate_invoice_at: 'Beginning of the current subscription period',
                days_until_due: 30,
                follow_calendar_months: 1,
                sales_tax_template: 'QC TPS 5% + TVQ 9.975% - T',
                custom_description: `${item.item_name} — ${item.rate}$/mois`,
                plans: planName ? [{ plan: planName, qty: item.qty }] : [],
              })
            } catch (e) {
              console.warn('[ProjectWizard] Subscription creation failed for', item.item_name, e.message)
            }
          }
        }
      }

      // Create Dispatch Jobs (tasks) — ONLY if NOT waiting for acceptance
      const createdJobs = []
      if (!needsAcceptance) {
        let ref = ''
        try { const rr = await fetch(`${HUB_URL}/dispatch/next-ref`); if (rr.ok) { const dd = await rr.json(); ref = dd.ref || '' } } catch (e) { /* repli ci-dessous */ }
        if (!ref) ref = 'DJ-' + Date.now().toString(36).toUpperCase()
        for (let i = 0; i < wizardSteps.value.length; i++) {
          const step = wizardSteps.value[i]
          const ticketId = `${ref}-s${i + 1}` // numéro standardisé YYYYMMDD-XXX-sN (remplace DJ-<base36>)

          let dependsOn = ''
          if (step.depends_on_step != null) {
            const depJob = createdJobs[step.depends_on_step]
            if (depJob) dependsOn = depJob.name
          }

          const parentJob = i > 0 && createdJobs[0] ? createdJobs[0].name : ''

          const newJob = await createJob({
            ticket_id: ticketId,
            subject: step.subject,
            address,
            duration_h: step.duration_h || 1,
            priority: step.priority || 'medium',
            status: 'open',
            job_type: step.job_type || 'Autre',
            source_issue: props.issue?.name || '',
            customer,
            service_location: serviceLocation,
            depends_on: dependsOn,
            parent_job: parentJob,
            step_order: i + 1,
            on_open_webhook: step.on_open_webhook || '',
            on_close_webhook: step.on_close_webhook || '',
            notes: [
              step.assigned_group ? `Groupe: ${step.assigned_group}` : '',
              orderDocName ? `${orderDocType}: ${orderDocName}` : '',
            ].filter(Boolean).join(' | '),
            scheduled_date: step.scheduled_date || '',
          })
          createdJobs.push(newJob)
        }
      }

      // Create Service Contract for residential commitments with recurring items
      // The contract IS the shopping-cart recap: recurring items drive duration/monthly_rate,
      // one-time items with regular_price > rate become "benefits" (promotions étalées).
      let contractName = ''
      const wantsContract = isQuotation && recurringItems.length > 0
        && recurringItems.some(i => (i.contract_months || 0) > 0)
      if (wantsContract) {
        try {
          const durationMonths = Math.max(...recurringItems.map(i => i.contract_months || 12))
          const monthlyRate = recurringItems.reduce((s, i) => s + (i.qty * i.rate), 0)
          // Prix original (barré) du forfait : somme des prix originaux si > marketing, sinon le marketing.
          const monthlyRegular = recurringItems.reduce(
            (s, i) => s + (i.qty * ((i.regular_price || 0) > i.rate ? i.regular_price : i.rate)), 0)
          const benefits = onetimeItems
            .filter(i => (i.regular_price || 0) > i.rate)
            .map(i => ({
              description: i.item_name,
              regular_price: i.regular_price,
              granted_price: i.rate,
            }))
          const contractType = acceptanceMethod.value === 'docuseal' ? 'Commercial' : 'Résidentiel'

          const createRes = await fetch(`${HUB_URL}/contract/create`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
              customer,
              contract_type: contractType,
              duration_months: durationMonths,
              monthly_rate: monthlyRate,
              monthly_regular: monthlyRegular > monthlyRate ? monthlyRegular : 0,
              install_fee: installFee?.value || 0,
              install_regular: (installRegular?.value || 0) > (installFee?.value || 0) ? installRegular.value : 0,
              service_location: serviceLocation,
              quotation: orderDocName,
              start_date: today,
              benefits,
            }),
          })
          const createData = await createRes.json()
          if (createData.ok && createData.contract) {
            contractName = createData.contract.name
            publishedContractName.value = contractName
          }
        } catch (e) {
          console.warn('[ProjectWizard] Service Contract creation failed:', e.message)
        }
      }

      // Generate acceptance link for quotations
      // When a Service Contract was created, prefer /contract/send (promotion-framed récap).
      // Otherwise fall back to the Quotation-centric /accept/generate flow.
      if (isQuotation && orderDocName && needsAcceptance) {
        try {
          if (contractName) {
            const sendRes = await fetch(`${HUB_URL}/contract/send`, {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({
                name: contractName,
                phone: clientPhone.value || '',
                email: clientEmail.value || '',
                use_docuseal: acceptanceMethod.value === 'docuseal',
              }),
            })
            const sendData = await sendRes.json()
            if (sendData.ok) {
              acceptanceLinkUrl.value = sendData.accept_link || sendData.sign_url || ''
              const viaParts = []
              if (sendData.method === 'sms') viaParts.push('SMS')
              if (sendData.method === 'docuseal') viaParts.push('DocuSeal')
              acceptanceSentVia.value = viaParts.length ? ` par ${viaParts.join(' et ')}` : ''
              acceptanceLinkSent.value = viaParts.length > 0
              Notify.create({
                type: 'info',
                message: sendData.method === 'docuseal'
                  ? 'Lien DocuSeal envoyé — contrat commercial'
                  : `Récapitulatif envoyé au client${acceptanceSentVia.value}`,
                timeout: 6000,
              })
            }
          } else {
            const acceptRes = await fetch(`${HUB_URL}/accept/generate`, {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({
                quotation: orderDocName,
                customer,
                ttl_hours: 168,
                send_sms: hasPhone,
                phone: clientPhone.value || '',
                send_email: hasEmail,
                email: clientEmail.value || '',
                use_docuseal: acceptanceMethod.value === 'docuseal',
                attach_pdf: true,
              }),
            })
            const acceptData = await acceptRes.json()
            if (acceptData.ok) {
              acceptanceLinkUrl.value = acceptData.link || acceptData.sign_url || ''
              const viaParts = []
              if (acceptData.sms_sent) viaParts.push('SMS')
              if (acceptData.email_sent) viaParts.push('courriel')
              acceptanceSentVia.value = viaParts.length ? ` par ${viaParts.join(' et ')}` : ''
              acceptanceLinkSent.value = viaParts.length > 0

              Notify.create({
                type: 'info',
                message: acceptData.method === 'docuseal'
                  ? 'Lien de signature DocuSeal envoyé au client'
                  : acceptanceLinkSent.value
                    ? `Lien d'acceptation envoyé${acceptanceSentVia.value}`
                    : 'Lien d\'acceptation généré — copiez-le pour l\'envoyer au client',
                timeout: 6000,
              })
            }
          }
        } catch (e) {
          console.warn('[ProjectWizard] Acceptance link failed:', e.message)
          acceptanceLinkUrl.value = `${HUB_URL}/accept/doc-pdf/Quotation/${encodeURIComponent(orderDocName)}`
        }
      }

      // Build notification
      const parts = []
      if (createdJobs.length) parts.push(`${createdJobs.length} tâches créées`)
      if (needsAcceptance) parts.push('en attente d\'acceptation')
      if (orderDocName) parts.push(`${orderDocType} ${orderDocName}`)
      if (contractName) parts.push(`Contrat ${contractName}`)
      if (!needsAcceptance && recurringItems.length) parts.push(`${recurringItems.length} abonnement(s)`)

      Notify.create({
        type: needsAcceptance ? 'warning' : 'positive',
        message: parts.join(' · '),
        timeout: 5000,
      })

      for (const job of createdJobs) {
        emit('created', job, { needsAcceptance }) // needsAcceptance → le parent peut enchaîner « Trouver un créneau » quand aucun contrat signé n'est requis
      }

      // Show success screen. Prefer Quotation as the primary artifact;
      // fall back to Service Contract when Quotation failed but Contract
      // landed — the rep still needs a way to retrieve the sommaire.
      if (orderDocName) {
        publishedDocName.value = orderDocName
        publishedDocType.value = orderDocType
        publishedDone.value = true
        pendingAcceptance.value = needsAcceptance
        publishedJobCount.value = createdJobs.length
        if (clientEmail.value) { sendTo.value = clientEmail.value; sendChannel.value = 'email' }
        else if (clientPhone.value) { sendTo.value = clientPhone.value; sendChannel.value = 'sms' }
      } else if (contractName) {
        publishedDocName.value = contractName
        publishedDocType.value = 'Service Contract'
        publishedDone.value = true
        pendingAcceptance.value = needsAcceptance
        publishedJobCount.value = createdJobs.length
      } else if (createdJobs.length) {
        publishedDocName.value = createdJobs[0]?.name || ''
        publishedDocType.value = 'Dispatch Job'
        publishedDone.value = true
        pendingAcceptance.value = false
        publishedJobCount.value = createdJobs.length
      } else {
        state.cancel()
      }
    } catch (err) {
      console.error('[ProjectWizard] publish error:', err)
      Notify.create({ type: 'negative', message: `Erreur: ${err.message || err}` })
    } finally {
      publishing.value = false
    }
  }

  return { publish }
}
