"""استيراد أوردرات إيزي أوردر (تصدير Excel/CSV) وحفظها بشكل منفصل.

الملف بيحتوي: ID, Phone, FullName, CreatedAt, Total Cost, Status,
Utm Source, Utm Campaign, Product Name ...
"""

import base64
import csv
import json
import os
import re
import ssl
import threading
import urllib.error
import urllib.request
from datetime import datetime, timedelta, timezone
try:
    from zoneinfo import ZoneInfo
    CAIRO = ZoneInfo('Africa/Cairo')
except Exception:  # لو السيرفر مفيهوش tzdata
    ZoneInfo = None
    CAIRO = timezone(timedelta(hours=2))


def _cairo_date(value):
    """يحوّل created_at (UTC غالباً) لتاريخ القاهرة."""
    text = str(value or '').strip()
    if not text:
        return ''
    try:
        dt = datetime.fromisoformat(text.replace('Z', '+00:00'))
        if dt.tzinfo is None:
            dt = dt.replace(tzinfo=timezone.utc)
        return dt.astimezone(CAIRO).strftime('%d-%m-%Y')
    except ValueError:
        if len(text) >= 10:
            try:
                return datetime.strptime(text[:10], '%Y-%m-%d').strftime('%d-%m-%Y')
            except ValueError:
                return ''
        return '', timedelta

import orders_import

DATA_DIR = os.path.dirname(os.path.abspath(__file__))
EASY_FILE = os.path.join(DATA_DIR, "orders_easy.csv")
STATE_FILE = os.path.join(DATA_DIR, "orders_state.json")

COLUMNS = ['id', 'phone', 'name', 'date', 'total', 'status',
           'utm_source', 'utm_campaign', 'items']


class EasyImportError(Exception):
    pass


def _excel_date(value):
    s = str(value or '').strip()
    if not s:
        return ''
    if re.fullmatch(r'\d+(\.\d+)?', s):
        try:
            num = float(s)
            if num > 20000:
                dt = datetime(1899, 12, 30) + timedelta(days=num)
                dt = dt.replace(tzinfo=timezone.utc).astimezone(CAIRO)
                return dt.strftime('%d-%m-%Y')
        except ValueError:
            pass
        return ''
    if 'T' in s or s.endswith('Z'):
        return _cairo_date(s)
    for fmt in ('%Y-%m-%d %H:%M:%S.%f', '%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M',
                '%Y-%m-%dT%H:%M:%S', '%Y-%m-%d', '%d-%m-%Y'):
        try:
            return datetime.strptime(s, fmt).strftime('%d-%m-%Y')
        except ValueError:
            continue
    return ''


def _num(value):
    s = str(value or '').replace(',', '').strip()
    try:
        return float(s)
    except ValueError:
        return 0.0


def parse_easy(blob):
    table = orders_import._read_xlsx(blob) if blob[:2] == b'PK' else orders_import._read_csv(blob)
    table = [r for r in table if any(str(c).strip() for c in r)]
    if not table:
        raise EasyImportError("الملف فاضي")

    header = [str(h).strip() for h in table[0]]
    idx = {h: i for i, h in enumerate(header) if h}

    required = ['ID', 'Phone', 'CreatedAt', 'Total Cost']
    missing = [c for c in required if c not in idx]
    if missing:
        raise EasyImportError("الملف مش تصدير أوردرات إيزي أوردر — ناقص: " + "، ".join(missing))

    def cell(row, name):
        i = idx.get(name)
        return str(row[i]).strip() if i is not None and i < len(row) and row[i] is not None else ''

    records = []
    for row in table[1:]:
        order_id = cell(row, 'ID')
        if not order_id:
            continue
        date = _excel_date(cell(row, 'CreatedAt'))
        if not date:
            continue
        source = cell(row, 'Utm Source').lower()
        if source == 'facebook':
            source = 'fb'
        records.append({
            'id': order_id,
            'phone': cell(row, 'Phone'),
            'name': cell(row, 'FullName'),
            'date': date,
            'total': _num(cell(row, 'Total Cost')),
            'status': cell(row, 'Status'),
            'utm_source': source,
            'utm_campaign': cell(row, 'Utm Campaign'),
            'items': cell(row, 'Product Name').replace('\n', ' | ')[:300],
        })
    if not records:
        raise EasyImportError("مفيش أوردرات صالحة في الملف")
    return records


_SAVE_LOCK = threading.Lock()


def save(records):
    with _SAVE_LOCK:
        merged = {r['id']: r for r in records}
        for old in load():
            merged.setdefault(old['id'], old)
        rows = sorted(merged.values(), key=lambda r: r['date'], reverse=True)
        tmp = EASY_FILE + '.tmp'
        with open(tmp, 'w', encoding='utf-8-sig', newline='') as f:
            writer = csv.DictWriter(f, fieldnames=COLUMNS, extrasaction='ignore')
            writer.writeheader()
            writer.writerows(rows)
        os.replace(tmp, EASY_FILE)
        return rows


def load():
    if not os.path.exists(EASY_FILE):
        return []
    with open(EASY_FILE, 'r', encoding='utf-8-sig', newline='') as f:
        return list(csv.DictReader(f))


def orders_page(start=None, end=None, source='الكل', q='', page=1, limit=25):
    rows = load()
    if start and end:
        try:
            s = datetime.strptime(start, '%Y-%m-%d').date()
            e = datetime.strptime(end, '%Y-%m-%d').date()
            rows = [r for r in rows
                    if r.get('date') and s <= datetime.strptime(r['date'], '%d-%m-%Y').date() <= e]
        except ValueError:
            pass
    if source and source != 'الكل':
        rows = [r for r in rows if (r.get('utm_source') or 'direct') == source]
    if q:
        needle = q.lower()
        rows = [r for r in rows
                if needle in f"{r.get('id','')} {r.get('name','')} {r.get('phone','')} {r.get('items','')}".lower()]
    def _sort_key(r):
        try:
            return (datetime.strptime(r.get('date', ''), '%d-%m-%Y'), int(r.get('id') or 0))
        except ValueError:
            return (datetime(1970, 1, 1), int(r.get('id') or 0))

    rows.sort(key=_sort_key, reverse=True)
    total = len(rows)
    page = max(1, int(page))
    limit = max(1, min(100, int(limit)))
    start_idx = (page - 1) * limit
    return {
        'total': total,
        'page': page,
        'limit': limit,
        'rows': rows[start_idx:start_idx + limit],
        'sources': summary().get('sources', {}),
    }


def summary():
    rows = load()
    dates = [r.get('date', '') for r in rows if r.get('date')]
    src = {}
    for r in rows:
        key = r.get('utm_source') or 'direct'
        src[key] = src.get(key, 0) + 1
    last_import = None
    if os.path.exists(STATE_FILE):
        try:
            with open(STATE_FILE, 'r', encoding='utf-8') as f:
                last_import = (json.load(f).get('easy') or {}).get('last_import')
        except Exception:
            last_import = None
    return {
        'source': 'easy',
        'rows': len(rows),
        'first_date': min(dates, key=_dk) if dates else '',
        'last_date': max(dates, key=_dk) if dates else '',
        'sources': src,
        'last_import': last_import,
    }


def _dk(value):
    try:
        return datetime.strptime(value, '%d-%m-%Y')
    except (TypeError, ValueError):
        return datetime.min


def record_from_api_order(order):
    """يبني سجل من رد Get Order API (فيه utm_source/utm_campaign)."""
    created = str(order.get('created_at') or '')
    date = _cairo_date(created)

    items = []
    for item in order.get('cart_items') or []:
        product = item.get('product') or {}
        if product.get('name'):
            items.append(product['name'])

    try:
        total = float(order.get('total_cost') or order.get('cost') or 0)
    except (TypeError, ValueError):
        total = 0.0

    return {
        'id': str(order.get('short_id') or order.get('id') or ''),
        'phone': str(order.get('phone') or ''),
        'name': str(order.get('full_name') or ''),
        'date': date,
        'total': total,
        'status': str(order.get('status') or ''),
        'utm_source': str(order.get('utm_source') or '').lower(),
        'utm_campaign': str(order.get('utm_campaign') or ''),
        'items': ' | '.join(items)[:300],
    }


def _api_key():
    try:
        import app
        return str(app.load_config().get('easyorders_api_key') or '')
    except Exception:  # noqa: BLE001
        return ''


def _ssl_ctx():
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE
    return ctx


def fetch_by_short(short_id, api_key=None):
    key = api_key or _api_key()
    if not key:
        return None
    url = f"https://api.easy-orders.net/api/v1/external-apps/orders/short/{short_id}"
    req = urllib.request.Request(url, headers={'Api-Key': key})
    try:
        with urllib.request.urlopen(req, context=_ssl_ctx(), timeout=20) as resp:
            return json.loads(resp.read().decode('utf-8', 'replace'))
    except Exception:  # noqa: BLE001
        return None


def max_id(rows=None):
    rows = rows if rows is not None else load()
    best = 0
    for r in rows:
        try:
            best = max(best, int(str(r.get('id') or 0)))
        except ValueError:
            continue
    return best


def sync_missing(scan=80):
    """يسحب الأوردرات الناقصة بعد آخر ID معروف (بدل الاعتماد على الويبهوك)."""
    rows = load()
    start = max_id(rows)
    added = []
    checked = 0
    misses = 0
    for sid in range(start + 1, start + 1 + scan):
        checked += 1
        order = fetch_by_short(sid)
        if not order:
            misses += 1
            if misses >= 25:
                break
            continue
        misses = 0
        record = record_from_api_order(order)
        if record.get('id') and record.get('date'):
            added.append(record)
    if added:
        save(added)
    return {
        'start_from': start,
        'checked': checked,
        'added': len(added),
        'new_max': max_id(),
        'rows': len(load()),
    }


def import_file(content, filename=''):
    blob = base64.b64decode(content) if isinstance(content, str) else content
    records = parse_easy(blob)
    rows = save(records)
    return {
        'rows': len(rows),
        'added': len(records),
        'first_date': summary()['first_date'],
        'last_date': summary()['last_date'],
    }
