import requests
import json
import os
import time
from datetime import datetime, timedelta

# 환경변수에서 카페24 인증 정보 로드
CLIENT_ID = os.getenv("CAFE24_CLIENT_ID", "")
CLIENT_SECRET = os.getenv("CAFE24_CLIENT_SECRET", "")
MALL_ID = os.getenv("CAFE24_MALL_ID", "miraskitchen")
REDIRECT_URI = os.getenv("CAFE24_REDIRECT_URI", "")
TOKEN_FILE = "cafe24_tokens.json"

def get_auth_url():
    # state parameter could be added for security but keeping it simple for local app
    url = f"https://{MALL_ID}.cafe24api.com/api/v2/oauth/authorize"
    url += f"?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}"
    url += f"&scope=mall.read_order,mall.write_order,mall.read_product"
    return url

import base64

def _get_basic_auth_header():
    credentials = f"{CLIENT_ID}:{CLIENT_SECRET}"
    encoded = base64.b64encode(credentials.encode('utf-8')).decode('utf-8')
    return f"Basic {encoded}"

def request_new_token(auth_code: str):
    url = f"https://{MALL_ID}.cafe24api.com/api/v2/oauth/token"
    headers = {
        "Authorization": _get_basic_auth_header(),
        "Content-Type": "application/x-www-form-urlencoded"
    }
    data = {
        "grant_type": "authorization_code",
        "code": auth_code,
        "redirect_uri": REDIRECT_URI
    }
    
    response = requests.post(url, headers=headers, data=data)
    if response.status_code == 200:
        _save_tokens(response.json())
        return True
    else:
        raise Exception(f"Failed to get token: {response.text}")

def refresh_access_token(refresh_token: str):
    url = f"https://{MALL_ID}.cafe24api.com/api/v2/oauth/token"
    headers = {
        "Authorization": _get_basic_auth_header(),
        "Content-Type": "application/x-www-form-urlencoded"
    }
    data = {
        "grant_type": "refresh_token",
        "refresh_token": refresh_token
    }
    
    response = requests.post(url, headers=headers, data=data)
    if response.status_code == 200:
        _save_tokens(response.json())
        return True
    else:
        # Refresh token might be expired. Need to re-authenticate.
        if os.path.exists(TOKEN_FILE):
            os.remove(TOKEN_FILE)
        raise Exception("Refresh token expired or invalid. Please re-authenticate.")

def _save_tokens(token_data):
    # Cafe24 returns expires_at in string format like "2023-10-01T12:00:00.000"
    if 'expires_at' not in token_data:
        # Fallback if expires_at is not provided (Cafe24 provides expires_at)
        expires_in = token_data.get('expires_in', 7200) # usually 2 hours
        expires_at = datetime.now() + timedelta(seconds=expires_in - 60) # 1 min buffer
        token_data['expires_at'] = expires_at.isoformat()
    
    with open(TOKEN_FILE, 'w', encoding='utf-8') as f:
        json.dump(token_data, f)

def get_valid_access_token():
    if not os.path.exists(TOKEN_FILE):
        raise Exception("No tokens found. Please authenticate first.")
        
    with open(TOKEN_FILE, 'r', encoding='utf-8') as f:
        tokens = json.load(f)
        
    expires_at_str = tokens.get('expires_at')
    # Parse Cafe24 typical datetime format or isoformat
    try:
        if '.' in expires_at_str: # e.g. "2023-10-01T12:00:00.000"
            expires_at = datetime.strptime(expires_at_str[:19], "%Y-%m-%dT%H:%M:%S")
        else:
            expires_at = datetime.fromisoformat(expires_at_str)
    except:
        expires_at = datetime.now() - timedelta(minutes=1) # force refresh on parse error
        
    # Check if expired
    if datetime.now() >= expires_at:
        print("Cafe24 Access token expired, refreshing...")
        refresh_access_token(tokens.get('refresh_token'))
        return get_valid_access_token()
        
    return tokens.get('access_token')

def get_cafe24_orders_count(status="N20"):
    token = get_valid_access_token()
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
        "X-Cafe24-Api-Version": "2026-03-01"
    }
    
    end_date = datetime.now().strftime("%Y-%m-%d")
    start_date = (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d")
    
    url = f"https://{MALL_ID}.cafe24api.com/api/v2/admin/orders/count"
    params = {
        "start_date": start_date,
        "end_date": end_date,
        "order_status": status
    }
    
    response = requests.get(url, headers=headers, params=params)
    if response.status_code == 200:
        return response.json().get('count', 0)
    return 0

def get_cafe24_orders(status="N20", progress_callback=None):
    """
    Fetch orders with specific status (default N20: 배송준비중)
    """
    token = get_valid_access_token()
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
        "X-Cafe24-Api-Version": "2026-03-01"
    }
    
    # Calculate search date range (e.g. last 7 days)
    end_date = datetime.now().strftime("%Y-%m-%d")
    start_date = (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d")
    
    url = f"https://{MALL_ID}.cafe24api.com/api/v2/admin/orders"
    
    all_orders = []
    limit = 100
    offset = 0
    
    while True:
        params = {
            "start_date": start_date,
            "end_date": end_date,
            "order_status": status,
            "limit": limit,
            "offset": offset,
            "embed": "receivers,items" # embed items and receiver addresses
        }
        
        response = requests.get(url, headers=headers, params=params)
        if response.status_code != 200:
            raise Exception(f"Failed to fetch Cafe24 orders: {response.text}")
            
        json_data = response.json()
        orders = json_data.get('orders', [])
        all_orders.extend(orders)
        
        if progress_callback:
            progress_callback(len(all_orders))
            
        if len(orders) < limit:
            break
            
        offset += limit
        time.sleep(0.5) # rate limit prevention
        
    return all_orders

def update_cafe24_tracking(dispatch_list):
    """
    dispatch_list is a list of dict: {"order_id": "...", "tracking_no": "...", "shipping_company_code": "0004"}
    Cafe24 API allows updating order shipments per order or item.
    Assuming we update the whole order (not item by item): PUT /api/v2/admin/orders/{order_id}/shipments
    """
    token = get_valid_access_token()
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
        "X-Cafe24-Api-Version": "2026-03-01"
    }
    
    results = {
        "success": [],
        "fail": []
    }
    
    for item in dispatch_list:
        order_id = item.get("order_id")
        tracking_no = item.get("tracking_no")
        company_code = item.get("shipping_company_code")
        
        url = f"https://{MALL_ID}.cafe24api.com/api/v2/admin/orders/{order_id}/shipments"
        payload = {
            "request": {
                "tracking_no": tracking_no,
                "shipping_company_code": company_code
            }
        }
        
        response = requests.put(url, headers=headers, json=payload)
        
        if response.status_code in [200, 201]:
            results["success"].append(order_id)
        else:
            reason = "Unknown Error"
            try:
                err_data = response.json()
                reason = err_data.get('error', {}).get('message', response.text)
            except:
                reason = response.text
                
            results["fail"].append({
                "order_id": order_id,
                "reason": reason
            })
            
        time.sleep(0.3) # API rate limit
        
    return results

def get_product_details(product_no):
    """ Fetch product details to get custom product codes/seller codes """
    token = get_valid_access_token()
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
        "X-Cafe24-Api-Version": "2026-03-01"
    }
    url = f"https://{MALL_ID}.cafe24api.com/api/v2/admin/products/{product_no}?embed=variants"
    
    response = requests.get(url, headers=headers)
    if response.status_code == 200:
        return response.json().get('product', {})
    return {}
