import telebot
import requests
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton

BOT_TOKEN = "7741492900:AAG6M_faLy5JG7g0t2gBFj-sXtBIaBXQZHk"
ALLOWED_USERS = [165067365]
CF_API_TOKEN = "VfeGnC3v5McJ3sJ6bsjjhG0IhvOgY-5-v6lpYgH3"

bot = telebot.TeleBot(BOT_TOKEN)
ZONE_CACHE = {}
USER_STATE = {}

def get_zones():
    headers = {"Authorization": f"Bearer {CF_API_TOKEN}"}
    r = requests.get("https://api.cloudflare.com/client/v4/zones", headers=headers).json()
    return r.get("result", [])

def get_zone_id(domain):
    root = ".".join(domain.split(".")[-2:])
    if root in ZONE_CACHE:
        return ZONE_CACHE[root]
    for z in get_zones():
        if z["name"] == root:
            ZONE_CACHE[root] = z["id"]
            return z["id"]
    return None

def is_authorized(uid):
    return uid in ALLOWED_USERS

def main_menu():
    markup = InlineKeyboardMarkup(row_width=2)
    markup.add(
        InlineKeyboardButton('➕ 添加记录', callback_data='add'),
        InlineKeyboardButton('🗑 删除记录', callback_data='del'),
        InlineKeyboardButton('☁️ 小黄云', callback_data='proxy'),
        InlineKeyboardButton('📋 列出记录', callback_data='list')
    )
    return markup

def domain_menu(action):
    zones = get_zones()
    markup = InlineKeyboardMarkup(row_width=2)
    for z in zones[:10]:
        markup.add(InlineKeyboardButton(z['name'], callback_data=f"{action}:{z['name']}"))
    markup.add(InlineKeyboardButton('🔙 返回', callback_data='back'))
    return markup

@bot.message_handler(commands=['help', 'start'])
def start_cmd(message):
    if not is_authorized(message.from_user.id): return
    bot.send_message(message.chat.id, '🌐 CF DNS 管理', reply_markup=main_menu())

@bot.callback_query_handler(func=lambda c: True)
def callback_handler(call):
    uid = call.from_user.id
    if not is_authorized(uid): return
    data = call.data

    if data == 'back':
        bot.edit_message_text('🌐 CF DNS 管理', call.message.chat.id, call.message.message_id, reply_markup=main_menu())
        return

    if data in ['add', 'del', 'proxy', 'list']:
        bot.edit_message_text(f'选择域名:', call.message.chat.id, call.message.message_id, reply_markup=domain_menu(data))
        return

    if data.startswith('list:'):
        domain = data.split(':')[1]
        zone_id = get_zone_id(domain)
        headers = {"Authorization": f"Bearer {CF_API_TOKEN}"}
        r = requests.get(f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records", headers=headers).json()
        records = r.get("result", [])
        if not records:
            txt = f'📋 {domain}\n\n无记录'
        else:
            lines = [f"{rec['name']} -> {rec['content']} ({'☁️' if rec['proxied'] else '⚪'})" for rec in records[:15]]
            txt = f'📋 {domain}\n\n' + '\n'.join(lines)
        markup = InlineKeyboardMarkup()
        markup.add(InlineKeyboardButton('🔙 返回', callback_data='back'))
        bot.edit_message_text(txt, call.message.chat.id, call.message.message_id, reply_markup=markup)
        return

    if data.startswith('add:'):
        domain = data.split(':')[1]
        USER_STATE[uid] = {'action': 'add', 'domain': domain}
        markup = InlineKeyboardMarkup()
        markup.add(InlineKeyboardButton('🔙 取消', callback_data='back'))
        bot.edit_message_text(f'➕ 添加记录到 {domain}\n\n请输入: 子域名 IP\n例如: www 1.2.3.4', call.message.chat.id, call.message.message_id, reply_markup=markup)
        return

    if data.startswith('del:'):
        domain = data.split(':')[1]
        zone_id = get_zone_id(domain)
        headers = {"Authorization": f"Bearer {CF_API_TOKEN}"}
        r = requests.get(f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records", headers=headers).json()
        records = r.get("result", [])
        markup = InlineKeyboardMarkup(row_width=1)
        for rec in records[:10]:
            short = rec['name'].replace(f'.{domain}', '') if rec['name'] != domain else '@'
            markup.add(InlineKeyboardButton(f"🗑 {short} -> {rec['content']}", callback_data=f"doit:{rec['id']}:{domain}"))
        markup.add(InlineKeyboardButton('🔙 返回', callback_data='back'))
        bot.edit_message_text(f'选择要删除的记录:', call.message.chat.id, call.message.message_id, reply_markup=markup)
        return

    if data.startswith('doit:'):
        parts = data.split(':')
        rec_id, domain = parts[1], parts[2]
        zone_id = get_zone_id(domain)
        headers = {"Authorization": f"Bearer {CF_API_TOKEN}"}
        requests.delete(f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records/{rec_id}", headers=headers)
        bot.answer_callback_query(call.id, '✅ 已删除')
        bot.edit_message_text('🌐 CF DNS 管理', call.message.chat.id, call.message.message_id, reply_markup=main_menu())
        return

    if data.startswith('proxy:'):
        domain = data.split(':')[1]
        zone_id = get_zone_id(domain)
        headers = {"Authorization": f"Bearer {CF_API_TOKEN}"}
        r = requests.get(f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records", headers=headers).json()
        records = r.get("result", [])
        markup = InlineKeyboardMarkup(row_width=1)
        for rec in records[:10]:
            short = rec['name'].replace(f'.{domain}', '') if rec['name'] != domain else '@'
            icon = '☁️' if rec['proxied'] else '⚪'
            markup.add(InlineKeyboardButton(f"{icon} {short} -> {rec['content']}", callback_data=f"toggle:{rec['id']}:{domain}"))
        markup.add(InlineKeyboardButton('🔙 返回', callback_data='back'))
        bot.edit_message_text(f'点击切换小黄云:', call.message.chat.id, call.message.message_id, reply_markup=markup)
        return

    if data.startswith('toggle:'):
        parts = data.split(':')
        rec_id, domain = parts[1], parts[2]
        zone_id = get_zone_id(domain)
        headers = {"Authorization": f"Bearer {CF_API_TOKEN}", "Content-Type": "application/json"}
        r = requests.get(f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records/{rec_id}", headers=headers).json()
        rec = r.get("result", {})
        new_state = not rec.get('proxied', False)
        requests.patch(f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records/{rec_id}", headers=headers, json={"proxied": new_state})
        bot.answer_callback_query(call.id, f"✅ 小黄云已{'开启' if new_state else '关闭'}")
        r = requests.get(f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records", headers=headers).json()
        records = r.get("result", [])
        markup = InlineKeyboardMarkup(row_width=1)
        for rec in records[:10]:
            short = rec['name'].replace(f'.{domain}', '') if rec['name'] != domain else '@'
            icon = '☁️' if rec['proxied'] else '⚪'
            markup.add(InlineKeyboardButton(f"{icon} {short} -> {rec['content']}", callback_data=f"toggle:{rec['id']}:{domain}"))
        markup.add(InlineKeyboardButton('🔙 返回', callback_data='back'))
        bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=markup)
        return

@bot.message_handler(func=lambda m: m.from_user.id in USER_STATE)
def handle_add(message):
    uid = message.from_user.id
    if not is_authorized(uid): return
    state = USER_STATE.get(uid)
    if not state or state['action'] != 'add': return

    parts = message.text.strip().split()
    if len(parts) < 2:
        bot.reply_to(message, '格式错误，请输入: 子域名 IP')
        return

    sub, ip = parts[0], parts[1]
    domain = state['domain']
    del USER_STATE[uid]

    zone_id = get_zone_id(domain)
    if not zone_id:
        bot.reply_to(message, f'找不到域名 {domain}')
        return
    name = f"{sub}.{domain}" if sub != '@' else domain
    headers = {"Authorization": f"Bearer {CF_API_TOKEN}", "Content-Type": "application/json"}
    data = {"type": "A", "name": name, "content": ip, "ttl": 1, "proxied": False}
    r = requests.post(f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records", headers=headers, json=data).json()
    if r.get("success"):
        bot.reply_to(message, f'✅ 添加成功: {name} -> {ip}', reply_markup=main_menu())
    else:
        bot.reply_to(message, f'❌ 失败: {r.get("errors", [])}')

if __name__ == '__main__':
    print('CF Bot 启动...')
    bot.infinity_polling()
