from flask import Flask, request, jsonify, redirect
from flask_cors import CORS
import json
import os
import random
import string
from datetime import datetime, timedelta

app = Flask(__name__)
# 配置CORS允许前端服务器访问
CORS(app, origins=[
    "http://192.168.1.100:8989",      # 前端服务器
    "http://localhost:8989",           # 本地测试
    "http://127.0.0.1:8989",          # 本地测试
    "http://short.shumengya.top",     # 前端域名（如果有）
    "https://short.shumengya.top"     # 前端域名HTTPS（如果有）
])

# 数据文件路径（支持持久化挂载）
DATA_DIR = os.getenv('DATA_DIR', '/app/data')
if not os.path.exists(DATA_DIR):
    os.makedirs(DATA_DIR)
DATA_FILE = os.path.join(DATA_DIR, 'link_data.json')

def load_links():
    """加载链接数据"""
    if not os.path.exists(DATA_FILE):
        return {}
    try:
        with open(DATA_FILE, 'r', encoding='utf-8') as f:
            return json.load(f)
    except:
        return {}

def save_links(links):
    """保存链接数据"""
    with open(DATA_FILE, 'w', encoding='utf-8') as f:
        json.dump(links, f, ensure_ascii=False, indent=2)

def clean_expired_links():
    """清理过期的链接"""
    links = load_links()
    current_time = datetime.now()
    expired_codes = []
    
    for code, data in links.items():
        expires_at = data.get('expires_at')
        if expires_at and expires_at != 'never':
            expire_time = datetime.fromisoformat(expires_at)
            if current_time > expire_time:
                expired_codes.append(code)
    
    for code in expired_codes:
        del links[code]
    
    if expired_codes:
        save_links(links)
    
    return len(expired_codes)

def is_link_expired(link_data):
    """检查链接是否过期"""
    expires_at = link_data.get('expires_at')
    if not expires_at or expires_at == 'never':
        return False
    
    expire_time = datetime.fromisoformat(expires_at)
    return datetime.now() > expire_time

def calculate_expire_time(expire_option):
    """计算过期时间"""
    if expire_option == 'never':
        return 'never'
    
    expire_map = {
        '10min': timedelta(minutes=10),
        '1hour': timedelta(hours=1),
        '1day': timedelta(days=1),
        '3days': timedelta(days=3),
        '1month': timedelta(days=30),
        '1year': timedelta(days=365)
    }
    
    delta = expire_map.get(expire_option)
    if delta:
        return (datetime.now() + delta).isoformat()
    return 'never'

def generate_random_code():
    """生成随机4位字母数字组合（包含大小写）"""
    chars = string.ascii_letters + string.digits  # a-zA-Z0-9
    return ''.join(random.choices(chars, k=4))



#==========================后端API接口==========================#
@app.route('/')
def index():
    """首页"""
    return jsonify({
        'message': '萌芽短链接分发系统',
        "author": "树萌芽",
        "API":
        {
            "/api/check/XXXX":"检查短链接是否已被使用",
            "/api/generate":"生成随机可用的短链接代码",
            "/api/create":"创建短链接",
            "/XXXX":"跳转到目标链接",
            "/api/links":"获取所有链接（可选功能）",
            "/api/redirect/XXXX":"API方式获取跳转链接（供前端路由使用）",
            "":"",

        }
    })

@app.route('/api/check/<code>', methods=['GET'])
def check_code(code):
    """检查短链接是否已被使用"""
    if len(code) != 4:
        return jsonify({'valid': False, 'message': '链接代码必须是4位字符'}), 400
    
    links = load_links()
    exists = code in links
    
    return jsonify({
        'exists': exists,
        'available': not exists
    })

@app.route('/api/generate', methods=['GET'])
def generate_code():
    """生成随机可用的短链接代码"""
    links = load_links()
    max_attempts = 100
    
    for _ in range(max_attempts):
        code = generate_random_code()
        if code not in links:
            return jsonify({
                'code': code,
                'success': True
            })
    
    return jsonify({
        'success': False,
        'message': '生成失败，请重试'
    }), 500

@app.route('/api/create', methods=['POST'])
def create_link():
    """创建短链接"""
    data = request.json
    code = data.get('code', '').strip()
    target_url = data.get('target_url', '').strip()
    expire_option = data.get('expire_option', 'never')
    
    # 验证输入
    if not code or not target_url:
        return jsonify({
            'success': False,
            'message': '链接代码和目标地址不能为空'
        }), 400
    
    if len(code) != 4:
        return jsonify({
            'success': False,
            'message': '链接代码必须是4位字符'
        }), 400
    
    # 清理过期链接
    clean_expired_links()
    
    # 检查是否已存在
    links = load_links()
    if code in links:
        return jsonify({
            'success': False,
            'message': '该链接代码已被使用，请选择其他代码'
        }), 409
    
    # 计算过期时间
    expires_at = calculate_expire_time(expire_option)
    
    # 保存链接
    links[code] = {
        'target_url': target_url,
        'created_at': datetime.now().isoformat(),
        'expires_at': expires_at,
        'expire_option': expire_option,
        'visit_count': 0
    }
    save_links(links)
    
    return jsonify({
        'success': True,
        'code': code,
        'short_url': f'short.shumengya.top/{code}',
        'expires_at': expires_at,
        'message': '短链接创建成功'
    })

@app.route('/<code>', methods=['GET'])
def redirect_link(code):
    """跳转到目标链接"""
    if len(code) != 4:
        return jsonify({
            'error': '无效的短链接',
            'message': '链接代码必须是4位字符'
        }), 404
    
    # 清理过期链接
    clean_expired_links()
    
    links = load_links()
    if code not in links:
        return jsonify({
            'error': '短链接不存在',
            'message': f'未找到代码为 {code} 的短链接'
        }), 404
    
    link_data = links[code]
    
    # 检查是否过期
    if is_link_expired(link_data):
        del links[code]
        save_links(links)
        return jsonify({
            'error': '短链接已过期',
            'message': f'代码为 {code} 的短链接已过期'
        }), 410
    
    # 增加访问次数
    link_data['visit_count'] = link_data.get('visit_count', 0) + 1
    links[code] = link_data
    save_links(links)
    
    target_url = link_data['target_url']
    
    # 确保URL包含协议
    if not target_url.startswith(('http://', 'https://')):
        target_url = 'http://' + target_url
    
    return redirect(target_url, code=302)

@app.route('/api/links', methods=['GET'])
def get_all_links():
    """获取所有链接（可选功能）"""
    # 清理过期链接
    clean_expired_links()
    
    links = load_links()
    return jsonify({
        'success': True,
        'count': len(links),
        'links': links
    })

@app.route('/api/redirect/<code>', methods=['GET'])
def api_redirect(code):
    """API方式获取跳转链接（供前端路由使用）"""
    if len(code) != 4:
        return jsonify({
            'success': False,
            'message': '链接代码必须是4位字符'
        }), 404
    
    # 清理过期链接
    clean_expired_links()
    
    links = load_links()
    if code not in links:
        return jsonify({
            'success': False,
            'message': f'未找到代码为 {code} 的短链接'
        }), 404
    
    link_data = links[code]
    
    # 检查是否过期
    if is_link_expired(link_data):
        del links[code]
        save_links(links)
        return jsonify({
            'success': False,
            'message': f'代码为 {code} 的短链接已过期'
        }), 410
    
    # 增加访问次数
    link_data['visit_count'] = link_data.get('visit_count', 0) + 1
    links[code] = link_data
    save_links(links)
    
    target_url = link_data['target_url']
    
    # 确保URL包含协议
    if not target_url.startswith(('http://', 'https://')):
        target_url = 'http://' + target_url
    
    return jsonify({
        'success': True,
        'code': code,
        'target_url': target_url
    })

@app.route('/api/stats/<code>', methods=['GET'])
def get_link_stats(code):
    """获取链接统计信息"""
    if len(code) != 4:
        return jsonify({
            'success': False,
            'message': '链接代码必须是4位字符'
        }), 404
    
    links = load_links()
    if code not in links:
        return jsonify({
            'success': False,
            'message': f'未找到代码为 {code} 的短链接'
        }), 404
    
    link_data = links[code]
    
    # 检查是否过期
    if is_link_expired(link_data):
        return jsonify({
            'success': False,
            'message': f'代码为 {code} 的短链接已过期',
            'expired': True
        }), 410
    
    return jsonify({
        'success': True,
        'code': code,
        'target_url': link_data['target_url'],
        'visit_count': link_data.get('visit_count', 0),
        'created_at': link_data.get('created_at'),
        'expires_at': link_data.get('expires_at'),
        'expire_option': link_data.get('expire_option')
    })

@app.route('/api/admin/delete/<code>', methods=['DELETE'])
def admin_delete_link(code):
    """管理员删除指定链接"""
    if len(code) != 4:
        return jsonify({
            'success': False,
            'message': '链接代码必须是4位字符'
        }), 400
    
    links = load_links()
    if code not in links:
        return jsonify({
            'success': False,
            'message': f'未找到代码为 {code} 的短链接'
        }), 404
    
    # 删除链接
    del links[code]
    save_links(links)
    
    return jsonify({
        'success': True,
        'message': f'成功删除短链接 {code}'
    })

@app.route('/api/admin/delete-batch', methods=['POST'])
def admin_delete_batch():
    """管理员批量删除链接"""
    data = request.json
    codes = data.get('codes', [])
    
    if not codes or not isinstance(codes, list):
        return jsonify({
            'success': False,
            'message': '请提供要删除的链接代码列表'
        }), 400
    
    links = load_links()
    deleted = []
    not_found = []
    
    for code in codes:
        if len(code) == 4 and code in links:
            del links[code]
            deleted.append(code)
        else:
            not_found.append(code)
    
    save_links(links)
    
    return jsonify({
        'success': True,
        'deleted': deleted,
        'deleted_count': len(deleted),
        'not_found': not_found,
        'message': f'成功删除 {len(deleted)} 个短链接'
    })

@app.route('/api/admin/clear-expired', methods=['POST'])
def admin_clear_expired():
    """管理员清理所有过期链接"""
    expired_count = clean_expired_links()
    
    return jsonify({
        'success': True,
        'cleared_count': expired_count,
        'message': f'成功清理 {expired_count} 个过期链接'
    })

#==========================后端API接口==========================#


if __name__ == '__main__':
    # 确保数据文件存在
    if not os.path.exists(DATA_FILE):
        save_links({})
    
    app.run(debug=True, host='0.0.0.0', port=5000)
