import datetime
import html as html_lib
import re
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError

from django.conf import settings
from django.utils import timezone

from .models import EmailSettings
from reports.services import dashboard_report, inventory_report, reorder_report, dead_stock_report

try:
    import resend
except ImportError:
    resend = None


PERIOD_LABELS = {
    'today': ('Daily Summary', 'Today'),
    'this_week': ('Weekly Summary', 'This Week'),
    'this_month': ('Monthly Summary', 'This Month'),
}


def _money(value):
    return f'{value:,.0f}'


def _e(value):
    """HTML-escape user-controlled text (part names/numbers) before it goes into the email body."""
    return html_lib.escape(str(value if value is not None else ''))


def html_to_text(html):
    """Plain-text alternative so clients/spam filters that dislike HTML-only mail are happy."""
    text = re.sub(r'(?i)<br\s*/?>|</(tr|p|h\d|div)>', '\n', html)
    text = re.sub(r'(?i)</t[dh]>', '  ', text)
    text = re.sub(r'<[^>]+>', '', text)
    text = html_lib.unescape(text)
    return re.sub(r'\n\s*\n+', '\n\n', re.sub(r'[ \t]+', ' ', text)).strip()


def compose_summary_email(period='today'):
    """Builds an HTML stock/sales summary email by reusing existing report calculations.

    Returns (subject, html) — no report logic of its own, just formatting.
    """
    dash = dashboard_report(period)
    inv = inventory_report()
    reorder = reorder_report()['reorder'][:10]
    dead = dead_stock_report(90)['dead_stock'][:10]

    today = dash['today']
    title, period_label = PERIOD_LABELS.get(period, PERIOD_LABELS['today'])
    subject = f'{settings.BUSINESS_NAME} — {title} ({timezone.localdate():%d %b %Y})'

    reorder_rows = ''.join(
        f'<tr><td style="padding:6px 10px;border-bottom:1px solid #e5e7eb;">{_e(r["name"])} ({_e(r["part_number"])})</td>'
        f'<td style="padding:6px 10px;border-bottom:1px solid #e5e7eb;text-align:right;">{r["quantity"]}</td>'
        f'<td style="padding:6px 10px;border-bottom:1px solid #e5e7eb;text-align:right;">{r["suggested_order_quantity"]}</td></tr>'
        for r in reorder
    ) or '<tr><td style="padding:10px;color:#94a3b8;" colspan="3">Nothing needs reordering</td></tr>'

    dead_rows = ''.join(
        f'<tr><td style="padding:6px 10px;border-bottom:1px solid #e5e7eb;">{_e(d["name"])} ({_e(d["part_number"])})</td>'
        f'<td style="padding:6px 10px;border-bottom:1px solid #e5e7eb;text-align:right;">{d["quantity"]}</td>'
        f'<td style="padding:6px 10px;border-bottom:1px solid #e5e7eb;text-align:right;">{_money(d["stock_value"])}</td></tr>'
        for d in dead
    ) or '<tr><td style="padding:10px;color:#94a3b8;" colspan="3">No dead stock right now</td></tr>'

    html = f"""
    <div style="font-family:Arial,Helvetica,sans-serif;max-width:640px;margin:0 auto;color:#0f172a;">
      <h2 style="margin-bottom:4px;">{_e(settings.BUSINESS_NAME)}</h2>
      <p style="color:#64748b;margin-top:0;">{title} for {timezone.localdate():%d %b %Y}</p>

      <table style="width:100%;border-collapse:collapse;margin:16px 0;">
        <tr>
          <td style="padding:12px;background:#eff6ff;border-radius:8px;width:33%;">
            <div style="font-size:12px;color:#64748b;text-transform:uppercase;">Sales · {period_label}</div>
            <div style="font-size:20px;font-weight:700;">{_money(today.get('sales_amount', 0))}</div>
          </td>
          <td style="width:8px;"></td>
          <td style="padding:12px;background:#f0fdf4;border-radius:8px;width:33%;">
            <div style="font-size:12px;color:#64748b;text-transform:uppercase;">Profit · {period_label}</div>
            <div style="font-size:20px;font-weight:700;">{_money(today.get('profit', 0))}</div>
          </td>
          <td style="width:8px;"></td>
          <td style="padding:12px;background:#fef2f2;border-radius:8px;width:33%;">
            <div style="font-size:12px;color:#64748b;text-transform:uppercase;">Low Stock</div>
            <div style="font-size:20px;font-weight:700;">{inv['low_stock_count']}</div>
          </td>
        </tr>
      </table>

      <h3 style="margin-bottom:6px;">Reorder Suggestions</h3>
      <table style="width:100%;border-collapse:collapse;font-size:13px;">
        <thead>
          <tr style="background:#f8fafc;text-align:left;">
            <th style="padding:6px 10px;">Part</th>
            <th style="padding:6px 10px;text-align:right;">Qty</th>
            <th style="padding:6px 10px;text-align:right;">Suggested</th>
          </tr>
        </thead>
        <tbody>{reorder_rows}</tbody>
      </table>

      <h3 style="margin-bottom:6px;margin-top:20px;">Dead Stock (90+ days)</h3>
      <table style="width:100%;border-collapse:collapse;font-size:13px;">
        <thead>
          <tr style="background:#f8fafc;text-align:left;">
            <th style="padding:6px 10px;">Part</th>
            <th style="padding:6px 10px;text-align:right;">Qty</th>
            <th style="padding:6px 10px;text-align:right;">Stock Value</th>
          </tr>
        </thead>
        <tbody>{dead_rows}</tbody>
      </table>

      <p style="color:#94a3b8;font-size:12px;margin-top:24px;">
        Automated summary from {_e(settings.BUSINESS_NAME)}. You are receiving this because your email
        is registered for scheduled reports.
      </p>
    </div>
    """
    return subject, html


class EmailSendError(Exception):
    pass


def get_email_config():
    """Effective Resend config: values saved in the app's Settings win; the environment is the fallback."""
    saved = EmailSettings.load()
    api_key = (saved.resend_api_key or getattr(settings, 'RESEND_API_KEY', '') or '').strip()
    from_email = (saved.from_email or getattr(settings, 'RESEND_FROM_EMAIL', '') or '').strip()
    return {
        'api_key': api_key,
        'from_email': from_email,
        'time_zone': saved.time_zone or settings.TIME_ZONE,
        'api_key_source': 'database' if saved.resend_api_key else ('environment' if api_key else 'none'),
        'from_email_source': 'database' if saved.from_email else ('environment' if from_email else 'none'),
    }


def get_zone(name=None):
    """The time zone report schedules are evaluated in; falls back to UTC if the saved name is invalid."""
    try:
        return ZoneInfo(name or get_email_config()['time_zone'])
    except (ZoneInfoNotFoundError, ValueError, KeyError):
        return ZoneInfo('UTC')


def send_via_resend(to, subject, html):
    """Send one email through Resend. Returns the Resend message id; raises EmailSendError on any failure."""
    if resend is None:
        raise EmailSendError('The resend package is not installed. Run: pip install -r requirements.txt')
    config = get_email_config()
    if not config['api_key'] or not config['from_email']:
        raise EmailSendError('Resend is not configured: set the API key and from-address in Settings → Email Reports.')

    resend.api_key = config['api_key']
    try:
        response = resend.Emails.send({
            'from': config['from_email'],
            'to': [to],
            'subject': subject,
            'html': html,
            'text': html_to_text(html),
        })
    except Exception as exc:
        raise EmailSendError(str(exc)[:240] or exc.__class__.__name__)
    message_id = response.get('id') if isinstance(response, dict) else getattr(response, 'id', None)
    if not message_id:
        raise EmailSendError('Resend accepted the request but returned no message id.')
    return message_id


def send_test_email(to):
    """Send a one-off connectivity check so setup can be verified without waiting for the schedule."""
    html = (
        f'<div style="font-family:Arial,sans-serif;"><h2>{_e(settings.BUSINESS_NAME)}</h2>'
        '<p>This is a test email. Resend is configured correctly and scheduled reports will arrive here.</p></div>'
    )
    return send_via_resend(to, f'{settings.BUSINESS_NAME} — test email', html)


def scheduled_datetime(recipient, now):
    """Today's send moment for `recipient`, in the same zone as `now`."""
    return now.replace(hour=recipient.send_hour, minute=recipient.send_minute, second=0, microsecond=0)


def is_due(recipient, now):
    """Whether `recipient` should be sent a report at `now` (an aware datetime in the email time zone).

    Due once per day: today matches the frequency, the chosen time has been reached, and nothing was
    successfully sent since that time. A late or missed cron run therefore still sends (catch-up)
    instead of silently skipping the whole day.
    """
    if not recipient.enabled:
        return False
    when = scheduled_datetime(recipient, now)
    if now < when:
        return False
    if recipient.frequency == recipient.Frequency.WEEKLY and now.weekday() != recipient.weekly_weekday:
        return False
    if recipient.frequency == recipient.Frequency.MONTHLY and now.day != 1:
        return False
    if recipient.pk and recipient.logs.filter(success=True, sent_at__gte=when).exists():
        return False
    return True


def sends_today_count(recipient, today):
    zone = get_zone()
    start = datetime.datetime.combine(today, datetime.time.min, tzinfo=zone)
    return recipient.logs.filter(sent_at__gte=start, sent_at__lt=start + datetime.timedelta(days=1), success=True).count()
