"""
Redmine MCP 服務器主程式
提供與 Redmine 系統整合的 MCP 工具
"""

import os
from typing import Any
from datetime import datetime

# 確保配置在 FastMCP 初始化之前載入
# 這會處理所有環境變數設定，包含 FASTMCP_LOG_LEVEL
from .config import get_config
config = get_config()

from mcp.server.fastmcp import FastMCP
from .redmine_client import get_client, RedmineAPIError

# 建立 FastMCP 服務器實例
mcp = FastMCP("Redmine MCP")


@mcp.tool()
def server_info() -> str:
    """取得服務器資訊和狀態"""
    config = get_config()
    return f"""Redmine MCP 服務器已啟動
- Redmine 網域: {config.redmine_domain}
- 除錯模式: {config.debug_mode}
- API 逾時: {config.redmine_timeout}秒"""


@mcp.tool()
def health_check() -> str:
    """健康檢查工具，確認服務器正常運作"""
    try:
        config = get_config()
        client = get_client()
        # 測試連線
        if client.test_connection():
            return f"✓ 服務器正常運作，已連接到 {config.redmine_domain}"
        else:
            return f"✗ 無法連接到 Redmine 服務器: {config.redmine_domain}"
    except Exception as e:
        return f"✗ 服務器異常: {str(e)}"


@mcp.tool()
def get_issue(issue_id: int, include_details: bool = True) -> str:
    """
    取得指定的 Redmine 議題詳細資訊
    
    Args:
        issue_id: 議題 ID
        include_details: 是否包含詳細資訊（描述、備註、附件等）
    
    Returns:
        議題的詳細資訊，以易讀格式呈現
    """
    try:
        client = get_client()
        include_params = []
        if include_details:
            include_params = ['attachments', 'changesets', 'children', 'journals', 'relations', 'watchers']
        
        # 使用新的 get_issue_raw 方法取得完整資料
        issue_data = client.get_issue_raw(issue_id, include=include_params)
        
        # 格式化基本議題資訊
        # 處理父議題資訊
        parent_info = "無父議題"
        if 'parent' in issue_data and issue_data['parent']:
            parent_info = f"#{issue_data['parent']['id']} - {issue_data['parent'].get('subject', 'N/A')}"
        
        result = f"""議題 #{issue_data['id']}: {issue_data['subject']}

基本資訊:
- 專案: {issue_data['project'].get('name', 'N/A')} (ID: {issue_data['project'].get('id', 'N/A')})
- 追蹤器: {issue_data['tracker'].get('name', 'N/A')}
- 狀態: {issue_data['status'].get('name', 'N/A')}
- 優先級: {issue_data['priority'].get('name', 'N/A')}
- 建立者: {issue_data['author'].get('name', 'N/A')}
- 指派給: {issue_data.get('assigned_to', {}).get('name', '未指派') if issue_data.get('assigned_to') else '未指派'}
- 父議題: {parent_info}
- 完成度: {issue_data.get('done_ratio', 0)}%
- 開始日期: {issue_data.get('start_date', '未設定')}
- 完成日期: {issue_data.get('due_date', '未設定')}
- 預估工時: {issue_data.get('estimated_hours', '未設定')} 小時
- 建立時間: {issue_data.get('created_on', 'N/A')}
- 更新時間: {issue_data.get('updated_on', 'N/A')}

描述:
{issue_data.get('description', '無描述')}"""

        # 加入附件資訊
        if include_details and 'attachments' in issue_data and issue_data['attachments']:
            result += f"\n\n附件 ({len(issue_data['attachments'])} 個):"
            for attachment in issue_data['attachments']:
                file_size = attachment.get('filesize', 0)
                file_size_mb = file_size / (1024 * 1024) if file_size > 0 else 0
                size_text = f"{file_size_mb:.2f} MB" if file_size_mb >= 1 else f"{file_size} bytes"
                
                result += f"""
- 檔名: {attachment.get('filename', 'N/A')}
  大小: {size_text}
  類型: {attachment.get('content_type', 'N/A')}
  上傳者: {attachment.get('author', {}).get('name', 'N/A')}
  上傳時間: {attachment.get('created_on', 'N/A')}
  下載連結: {client.config.redmine_domain}/attachments/download/{attachment.get('id', '')}/{attachment.get('filename', '')}"""

        # 加入備註/歷史記錄
        if include_details and 'journals' in issue_data and issue_data['journals']:
            # 過濾出有備註內容的記錄
            notes_journals = [j for j in issue_data['journals'] if j.get('notes', '').strip()]
            
            if notes_journals:
                result += f"\n\n備註/歷史記錄 ({len(notes_journals)} 筆):"
                for i, journal in enumerate(notes_journals, 1):
                    author_name = journal.get('user', {}).get('name', 'N/A')
                    created_on = journal.get('created_on', 'N/A')
                    notes = journal.get('notes', '').strip()
                    
                    result += f"""

#{i} - {author_name} ({created_on}):
{notes}"""

        return result
        
    except RedmineAPIError as e:
        return f"取得議題失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def update_issue_status(issue_id: int, status_id: int = None, status_name: str = None, notes: str = "") -> str:
    """
    更新議題狀態
    
    Args:
        issue_id: 議題 ID
        status_id: 新的狀態 ID（與 status_name 二選一）
        status_name: 新的狀態名稱（與 status_id 二選一）
        notes: 更新備註（可選）
    
    Returns:
        更新結果訊息
    """
    try:
        client = get_client()
        
        # 處理狀態參數
        final_status_id = status_id
        if status_name:
            final_status_id = client.find_status_id_by_name(status_name)
            if not final_status_id:
                return f"找不到狀態名稱：「{status_name}」\n\n可用狀態：\n" + "\n".join([f"- {name}" for name in client.get_available_statuses().keys()])
        
        if not final_status_id:
            return "錯誤：必須提供 status_id 或 status_name 其中一個參數"
        
        # 準備更新資料
        update_data = {'status_id': final_status_id}
        if notes.strip():
            update_data['notes'] = notes.strip()
        
        # 執行更新
        client.update_issue(issue_id, **update_data)
        
        # 取得更新後的議題資訊確認
        updated_issue = client.get_issue(issue_id)
        
        result = f"""議題狀態更新成功!

議題: #{issue_id} - {updated_issue.subject}
新狀態: {updated_issue.status.get('name', 'N/A')}"""

        if notes.strip():
            result += f"\n備註: {notes}"
            
        return result
        
    except RedmineAPIError as e:
        return f"更新議題狀態失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def list_project_issues(project_id: int, status_filter: str = "open", limit: int = 20) -> str:
    """
    列出專案的議題
    
    Args:
        project_id: 專案 ID
        status_filter: 狀態篩選 ("open", "closed", "all")
        limit: 最大回傳數量 (預設 20，最大 100)
    
    Returns:
        專案議題列表，以表格格式呈現
    """
    try:
        client = get_client()
        
        # 限制 limit 範圍
        limit = min(max(limit, 1), 100)
        
        # 根據狀態篩選設定參數
        params = {
            'project_id': project_id,
            'limit': limit,
            'sort': 'updated_on:desc'
        }
        
        # 處理狀態篩選
        if status_filter == "open":
            params['status_id'] = 'o'  # Redmine API 使用 'o' 表示開放狀態
        elif status_filter == "closed":
            params['status_id'] = 'c'  # Redmine API 使用 'c' 表示關閉狀態
        # "all" 則不設定 status_id
        
        # 取得議題列表
        issues = client.list_issues(**params)
        
        if not issues:
            return f"專案 {project_id} 中沒有找到符合條件的議題"
        
        # 取得專案資訊
        try:
            project = client.get_project(project_id)
            project_name = project.name
        except:
            project_name = f"專案 {project_id}"
        
        # 格式化議題列表
        result = f"""專案: {project_name}
狀態篩選: {status_filter}
找到 {len(issues)} 個議題:

{"ID":<8} {"標題":<40} {"狀態":<12} {"指派給":<15} {"更新時間":<10}
{"-"*8} {"-"*40} {"-"*12} {"-"*15} {"-"*10}"""

        for issue in issues:
            title = issue.subject[:37] + "..." if len(issue.subject) > 40 else issue.subject
            status = issue.status.get('name', 'N/A')[:10]
            assignee = issue.assigned_to.get('name', '未指派')[:13] if issue.assigned_to else '未指派'
            updated = issue.updated_on[:10] if issue.updated_on else 'N/A'
            
            result += f"\n{issue.id:<8} {title:<40} {status:<12} {assignee:<15} {updated:<10}"
        
        return result
        
    except RedmineAPIError as e:
        return f"列出專案議題失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def get_issue_statuses() -> str:
    """
    取得所有可用的議題狀態列表
    
    Returns:
        格式化的狀態列表
    """
    try:
        client = get_client()
        statuses = client.get_issue_statuses()
        
        if not statuses:
            return "沒有找到議題狀態"
        
        result = "可用的議題狀態:\n\n"
        result += f"{'ID':<5} {'名稱':<15} {'已關閉':<8}\n"
        result += f"{'-'*5} {'-'*15} {'-'*8}\n"
        
        for status in statuses:
            is_closed = "是" if status.get('is_closed', False) else "否"
            result += f"{status['id']:<5} {status['name']:<15} {is_closed:<8}\n"
        
        return result
        
    except RedmineAPIError as e:
        return f"取得議題狀態失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def get_trackers() -> str:
    """
    取得所有可用的追蹤器列表
    
    Returns:
        格式化的追蹤器列表
    """
    try:
        client = get_client()
        trackers = client.get_trackers()
        
        if not trackers:
            return "沒有找到追蹤器"
        
        result = "可用的追蹤器:\n\n"
        result += f"{'ID':<5} {'名稱':<20} {'預設狀態':<12}\n"
        result += f"{'-'*5} {'-'*20} {'-'*12}\n"
        
        for tracker in trackers:
            default_status = tracker.get('default_status', {}).get('name', 'N/A')
            result += f"{tracker['id']:<5} {tracker['name']:<20} {default_status:<12}\n"
        
        return result
        
    except RedmineAPIError as e:
        return f"取得追蹤器列表失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def get_priorities() -> str:
    """
    取得所有可用的議題優先級列表
    
    Returns:
        格式化的優先級列表
    """
    try:
        client = get_client()
        priorities = client.get_priorities()
        
        if not priorities:
            return "沒有找到議題優先級"
        
        result = "可用的議題優先級:\n\n"
        result += f"{'ID':<5} {'名稱':<15} {'預設':<8}\n"
        result += f"{'-'*5} {'-'*15} {'-'*8}\n"
        
        for priority in priorities:
            is_default = "是" if priority.get('is_default', False) else "否"
            result += f"{priority['id']:<5} {priority['name']:<15} {is_default:<8}\n"
        
        return result
        
    except RedmineAPIError as e:
        return f"取得議題優先級失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def get_time_entry_activities() -> str:
    """
    取得所有可用的時間追蹤活動列表
    
    Returns:
        格式化的時間追蹤活動列表
    """
    try:
        client = get_client()
        activities = client.get_time_entry_activities()
        
        if not activities:
            return "沒有找到時間追蹤活動"
        
        result = "可用的時間追蹤活動:\n\n"
        result += f"{'ID':<5} {'名稱':<20} {'預設':<8}\n"
        result += f"{'-'*5} {'-'*20} {'-'*8}\n"
        
        for activity in activities:
            is_default = "是" if activity.get('is_default', False) else "否"
            result += f"{activity['id']:<5} {activity['name']:<20} {is_default:<8}\n"
        
        return result
        
    except RedmineAPIError as e:
        return f"取得時間追蹤活動失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def get_document_categories() -> str:
    """
    取得所有可用的文件分類列表
    
    Returns:
        格式化的文件分類列表
    """
    try:
        client = get_client()
        categories = client.get_document_categories()
        
        if not categories:
            return "沒有找到文件分類"
        
        result = "可用的文件分類:\n\n"
        result += f"{'ID':<5} {'名稱':<25} {'預設':<8}\n"
        result += f"{'-'*5} {'-'*25} {'-'*8}\n"
        
        for category in categories:
            is_default = "是" if category.get('is_default', False) else "否"
            result += f"{category['id']:<5} {category['name']:<25} {is_default:<8}\n"
        
        return result
        
    except RedmineAPIError as e:
        return f"取得文件分類失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def get_projects() -> str:
    """
    取得可存取的專案列表
    
    Returns:
        格式化的專案列表
    """
    try:
        client = get_client()
        projects = client.list_projects(limit=50)
        
        if not projects:
            return "沒有找到可存取的專案"
        
        result = f"找到 {len(projects)} 個專案:\n\n"
        result += f"{'ID':<5} {'識別碼':<20} {'名稱':<30} {'狀態':<8}\n"
        result += f"{'-'*5} {'-'*20} {'-'*30} {'-'*8}\n"
        
        for project in projects:
            status_text = "正常" if project.status == 1 else "封存"
            name = project.name[:27] + "..." if len(project.name) > 30 else project.name
            result += f"{project.id:<5} {project.identifier:<20} {name:<30} {status_text:<8}\n"
        
        return result
        
    except RedmineAPIError as e:
        return f"取得專案列表失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def search_issues(query: str, project_id: int = None, limit: int = 10) -> str:
    """
    搜尋議題 (在標題或描述中搜尋關鍵字)
    
    Args:
        query: 搜尋關鍵字
        project_id: 限制在特定專案中搜尋 (可選)
        limit: 最大回傳數量 (預設 10，最大 50)
    
    Returns:
        符合搜尋條件的議題列表
    """
    try:
        if not query.strip():
            return "請提供搜尋關鍵字"
        
        client = get_client()
        limit = min(max(limit, 1), 50)
        
        # 設定搜尋參數
        params = {
            'limit': limit * 3,  # 取得更多結果以便篩選
            'sort': 'updated_on:desc'
        }
        
        if project_id:
            params['project_id'] = project_id
        
        # 取得議題列表
        all_issues = client.list_issues(**params)
        
        # 在本地端進行關鍵字篩選 (因為 Redmine API 沒有內建搜尋)
        query_lower = query.lower()
        matching_issues = []
        
        for issue in all_issues:
            if (query_lower in issue.subject.lower() or 
                (issue.description and query_lower in issue.description.lower())):
                matching_issues.append(issue)
                if len(matching_issues) >= limit:
                    break
        
        if not matching_issues:
            search_scope = f"專案 {project_id}" if project_id else "所有可存取的專案"
            return f"在 {search_scope} 中沒有找到包含 '{query}' 的議題"
        
        # 格式化結果
        result = f"搜尋關鍵字: '{query}'\n"
        if project_id:
            result += f"搜尋範圍: 專案 {project_id}\n"
        result += f"找到 {len(matching_issues)} 個相關議題:\n\n"
        
        result += f"{'ID':<8} {'標題':<35} {'狀態':<12} {'專案':<15}\n"
        result += f"{'-'*8} {'-'*35} {'-'*12} {'-'*15}\n"
        
        for issue in matching_issues:
            title = issue.subject[:32] + "..." if len(issue.subject) > 35 else issue.subject
            status = issue.status.get('name', 'N/A')[:10]
            project_name = issue.project.get('name', 'N/A')[:13]
            
            result += f"{issue.id:<8} {title:<35} {status:<12} {project_name:<15}\n"
        
        return result
        
    except RedmineAPIError as e:
        return f"搜尋議題失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def update_issue_content(issue_id: int, subject: str = None, description: str = None, 
                        priority_id: int = None, priority_name: str = None,
                        done_ratio: int = None, tracker_id: int = None, tracker_name: str = None,
                        parent_issue_id: int = None, remove_parent: bool = False, start_date: str = None, due_date: str = None,
                        estimated_hours: float = None) -> str:
    """
    更新議題內容（標題、描述、優先級、完成度、追蹤器、日期、工時等）
    
    Args:
        issue_id: 議題 ID
        subject: 新的議題標題（可選）
        description: 新的議題描述（可選）
        priority_id: 新的優先級 ID（與 priority_name 二選一）
        priority_name: 新的優先級名稱（與 priority_id 二選一）
        done_ratio: 新的完成百分比 0-100（可選）
        tracker_id: 新的追蹤器 ID（與 tracker_name 二選一）
        tracker_name: 新的追蹤器名稱（與 tracker_id 二選一）
        parent_issue_id: 新的父議題 ID（可選）
        remove_parent: 是否移除父議題關係（可選）
        start_date: 新的開始日期 YYYY-MM-DD 格式（可選）
        due_date: 新的完成日期 YYYY-MM-DD 格式（可選）
        estimated_hours: 新的預估工時（可選）
    
    Returns:
        更新結果訊息
    """
    try:
        client = get_client()
        
        # 準備更新資料
        update_data = {}
        changes = []
        
        if subject is not None:
            update_data['subject'] = subject.strip()
            changes.append(f"標題: {subject}")
        
        if description is not None:
            update_data['description'] = description
            changes.append("描述已更新")
        
        # 處理優先級參數
        if priority_name:
            priority_id = client.find_priority_id_by_name(priority_name)
            if not priority_id:
                return f"找不到優先級名稱：「{priority_name}」\n\n可用優先級：\n" + "\n".join([f"- {name}" for name in client.get_available_priorities().keys()])
        
        if priority_id is not None:
            update_data['priority_id'] = priority_id
            changes.append(f"優先級 ID: {priority_id}")
        
        if done_ratio is not None:
            if not (0 <= done_ratio <= 100):
                return "錯誤: 完成百分比必須在 0-100 之間"
            update_data['done_ratio'] = done_ratio
            changes.append(f"完成度: {done_ratio}%")
        
        # 處理追蹤器參數
        if tracker_name:
            tracker_id = client.find_tracker_id_by_name(tracker_name)
            if not tracker_id:
                return f"找不到追蹤器名稱：「{tracker_name}」\n\n可用追蹤器：\n" + "\n".join([f"- {name}" for name in client.get_available_trackers().keys()])
        
        if tracker_id is not None:
            update_data['tracker_id'] = tracker_id
            changes.append(f"追蹤器 ID: {tracker_id}")
        
        if remove_parent:
            update_data['parent_issue_id'] = None
            changes.append("移除父議題關係")
        elif parent_issue_id is not None:
            update_data['parent_issue_id'] = parent_issue_id
            changes.append(f"父議題 ID: {parent_issue_id}")
        
        if start_date is not None:
            # 驗證日期格式
            try:
                from datetime import datetime
                datetime.strptime(start_date, '%Y-%m-%d')
                update_data['start_date'] = start_date
                changes.append(f"開始日期: {start_date}")
            except ValueError:
                return "錯誤: 開始日期格式必須為 YYYY-MM-DD"
        
        if due_date is not None:
            # 驗證日期格式
            try:
                from datetime import datetime
                datetime.strptime(due_date, '%Y-%m-%d')
                update_data['due_date'] = due_date
                changes.append(f"完成日期: {due_date}")
            except ValueError:
                return "錯誤: 完成日期格式必須為 YYYY-MM-DD"
        
        if estimated_hours is not None:
            if estimated_hours < 0:
                return "錯誤: 預估工時不能為負數"
            update_data['estimated_hours'] = estimated_hours
            changes.append(f"預估工時: {estimated_hours} 小時")
        
        if not update_data and not changes:
            return "錯誤: 請至少提供一個要更新的欄位"
        
        # 執行更新
        client.update_issue(issue_id, **update_data)
        
        # 取得更新後的議題資訊
        updated_issue = client.get_issue(issue_id)
        
        result = f"""議題內容更新成功!

議題: #{issue_id} - {updated_issue.subject}
已更新的欄位:
{chr(10).join(f"- {change}" for change in changes)}

目前狀態:
- 追蹤器: {updated_issue.tracker.get('name', 'N/A')}
- 狀態: {updated_issue.status.get('name', 'N/A')}
- 優先級: {updated_issue.priority.get('name', 'N/A')}
- 完成度: {updated_issue.done_ratio}%"""

        return result
        
    except RedmineAPIError as e:
        return f"更新議題內容失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def add_issue_note(issue_id: int, notes: str, private: bool = False, 
                   spent_hours: float = None, activity_name: str = None, 
                   activity_id: int = None, spent_on: str = None) -> str:
    """
    為議題新增備註，可同時記錄時間
    
    Args:
        issue_id: 議題 ID
        notes: 備註內容
        private: 是否為私有備註（預設否）
        spent_hours: 耗用工時（小時）
        activity_name: 活動名稱（與 activity_id 二選一）
        activity_id: 活動 ID（與 activity_name 二選一）
        spent_on: 記錄日期 YYYY-MM-DD 格式（可選，預設今日）
    
    Returns:
        新增結果訊息
    """
    try:
        if not notes.strip():
            return "錯誤: 備註內容不能為空"
        
        client = get_client()
        time_entry_id = None
        
        # 處理時間記錄
        if spent_hours is not None:
            if spent_hours <= 0:
                return "錯誤: 耗用工時必須大於 0"
            
            # 處理活動參數
            final_activity_id = activity_id
            if activity_name:
                final_activity_id = client.find_time_entry_activity_id_by_name(activity_name)
                if not final_activity_id:
                    available_activities = client.get_available_time_entry_activities()
                    return f"找不到時間追蹤活動名稱：「{activity_name}」\n\n可用活動：\n" + "\n".join([f"- {name}" for name in available_activities.keys()])
            
            if not final_activity_id:
                return "錯誤: 必須提供 activity_id 或 activity_name 參數"
            
            # 建立時間記錄
            try:
                time_entry_id = client.create_time_entry(
                    issue_id=issue_id,
                    hours=spent_hours,
                    activity_id=final_activity_id,
                    comments=notes.strip(),
                    spent_on=spent_on
                )
            except Exception as e:
                return f"建立時間記錄失敗: {str(e)}"
        
        # 準備更新資料（新增備註）
        update_data = {'notes': notes.strip()}
        if private:
            update_data['private_notes'] = True
        
        # 執行更新
        client.update_issue(issue_id, **update_data)
        
        # 取得議題資訊
        issue = client.get_issue(issue_id)
        
        privacy_text = "私有" if private else "公開"
        result = f"""備註新增成功!

議題: #{issue_id} - {issue.subject}
備註類型: {privacy_text}
備註內容:
{notes.strip()}"""

        # 如果有建立時間記錄，添加相關資訊
        if time_entry_id:
            from datetime import date
            actual_date = spent_on if spent_on else date.today().strftime('%Y-%m-%d')
            activity_name_display = activity_name if activity_name else f"ID {final_activity_id}"
            result += f"""

時間記錄新增成功!
- 時間記錄 ID: {time_entry_id}
- 耗用工時: {spent_hours} 小時
- 活動: {activity_name_display}
- 記錄日期: {actual_date}"""

        return result
        
    except RedmineAPIError as e:
        return f"新增議題備註失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def assign_issue(issue_id: int, user_id: int = None, user_name: str = None, user_login: str = None, notes: str = "") -> str:
    """
    指派議題給用戶
    
    Args:
        issue_id: 議題 ID
        user_id: 指派給的用戶 ID（與 user_name/user_login 三選一）
        user_name: 指派給的用戶姓名（與 user_id/user_login 三選一）
        user_login: 指派給的用戶登入名（與 user_id/user_name 三選一）
        notes: 指派備註（可選）
    
    Returns:
        指派結果訊息
    """
    try:
        client = get_client()
        
        # 處理用戶參數
        final_user_id = user_id
        if user_name:
            final_user_id = client.find_user_id_by_name(user_name)
            if not final_user_id:
                users = client.get_available_users()
                return f"找不到用戶姓名：「{user_name}」\n\n可用用戶（姓名）：\n" + "\n".join([f"- {name}" for name in users['by_name'].keys()])
        elif user_login:
            final_user_id = client.find_user_id_by_login(user_login)
            if not final_user_id:
                users = client.get_available_users()
                return f"找不到用戶登入名：「{user_login}」\n\n可用用戶（登入名）：\n" + "\n".join([f"- {login}" for login in users['by_login'].keys()])
        
        # 準備更新資料
        update_data = {}
        
        if final_user_id is not None:
            update_data['assigned_to_id'] = final_user_id
            action_text = f"指派給用戶 ID {final_user_id}"
        else:
            update_data['assigned_to_id'] = None
            action_text = "取消指派"
        
        if notes.strip():
            update_data['notes'] = notes.strip()
        
        # 執行更新
        client.update_issue(issue_id, **update_data)
        
        # 取得更新後的議題資訊
        updated_issue = client.get_issue(issue_id)
        
        assignee_name = "未指派"
        if updated_issue.assigned_to:
            assignee_name = updated_issue.assigned_to.get('name', f"用戶 ID {user_id}")
        
        result = f"""議題指派更新成功!

議題: #{issue_id} - {updated_issue.subject}
動作: {action_text}
目前指派給: {assignee_name}"""

        if notes.strip():
            result += f"\n備註: {notes}"

        return result
        
    except RedmineAPIError as e:
        return f"指派議題失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def create_new_issue(project_id: int, subject: str, description: str = "", 
                    tracker_id: int = None, tracker_name: str = None,
                    priority_id: int = None, priority_name: str = None,
                    assigned_to_id: int = None, assigned_to_name: str = None, assigned_to_login: str = None) -> str:
    """
    建立新的 Redmine 議題
    
    Args:
        project_id: 專案 ID
        subject: 議題標題
        description: 議題描述（可選）
        tracker_id: 追蹤器 ID（與 tracker_name 二選一）
        tracker_name: 追蹤器名稱（與 tracker_id 二選一）
        priority_id: 優先級 ID（與 priority_name 二選一）
        priority_name: 優先級名稱（與 priority_id 二選一）
        assigned_to_id: 指派給的用戶 ID（與 assigned_to_name/assigned_to_login 三選一）
        assigned_to_name: 指派給的用戶姓名（與 assigned_to_id/assigned_to_login 三選一）
        assigned_to_login: 指派給的用戶登入名（與 assigned_to_id/assigned_to_name 三選一）
    
    Returns:
        建立結果訊息
    """
    try:
        if not subject.strip():
            return "錯誤: 議題標題不能為空"
        
        client = get_client()
        
        # 處理追蹤器參數
        final_tracker_id = tracker_id
        if tracker_name:
            final_tracker_id = client.find_tracker_id_by_name(tracker_name)
            if not final_tracker_id:
                return f"找不到追蹤器名稱：「{tracker_name}」\n\n可用追蹤器：\n" + "\n".join([f"- {name}" for name in client.get_available_trackers().keys()])
        
        # 處理優先級參數
        final_priority_id = priority_id
        if priority_name:
            final_priority_id = client.find_priority_id_by_name(priority_name)
            if not final_priority_id:
                return f"找不到優先級名稱：「{priority_name}」\n\n可用優先級：\n" + "\n".join([f"- {name}" for name in client.get_available_priorities().keys()])
        
        # 處理指派用戶參數
        final_assigned_to_id = assigned_to_id
        if assigned_to_name:
            final_assigned_to_id = client.find_user_id_by_name(assigned_to_name)
            if not final_assigned_to_id:
                users = client.get_available_users()
                return f"找不到用戶姓名：「{assigned_to_name}」\n\n可用用戶（姓名）：\n" + "\n".join([f"- {name}" for name in users['by_name'].keys()])
        elif assigned_to_login:
            final_assigned_to_id = client.find_user_id_by_login(assigned_to_login)
            if not final_assigned_to_id:
                users = client.get_available_users()
                return f"找不到用戶登入名：「{assigned_to_login}」\n\n可用用戶（登入名）：\n" + "\n".join([f"- {login}" for login in users['by_login'].keys()])
        
        # 建立議題
        new_issue_id = client.create_issue(
            project_id=project_id,
            subject=subject.strip(),
            description=description,
            tracker_id=final_tracker_id,
            priority_id=final_priority_id,
            assigned_to_id=final_assigned_to_id
        )
        
        # 取得建立的議題資訊
        new_issue = client.get_issue(new_issue_id)
        
        result = f"""新議題建立成功!

議題 ID: #{new_issue_id}
標題: {new_issue.subject}
專案: {new_issue.project.get('name', 'N/A')}
追蹤器: {new_issue.tracker.get('name', 'N/A')}
狀態: {new_issue.status.get('name', 'N/A')}
優先級: {new_issue.priority.get('name', 'N/A')}
指派給: {new_issue.assigned_to.get('name', '未指派') if new_issue.assigned_to else '未指派'}"""

        if description:
            result += f"\n\n描述:\n{description}"

        return result
        
    except RedmineAPIError as e:
        return f"建立議題失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def get_my_issues(status_filter: str = "open", limit: int = 20) -> str:
    """
    取得指派給我的議題列表
    
    Args:
        status_filter: 狀態篩選 ("open", "closed", "all")
        limit: 最大回傳數量 (預設 20，最大 100)
    
    Returns:
        我的議題列表
    """
    try:
        client = get_client()
        
        # 先取得當前用戶資訊
        current_user = client.get_current_user()
        user_id = current_user['id']
        user_name = current_user.get('firstname', '') + ' ' + current_user.get('lastname', '')
        
        # 限制 limit 範圍
        limit = min(max(limit, 1), 100)
        
        # 設定查詢參數
        params = {
            'assigned_to_id': user_id,
            'limit': limit,
            'sort': 'updated_on:desc'
        }
        
        # 處理狀態篩選
        if status_filter == "open":
            params['status_id'] = 'o'  # Redmine API 使用 'o' 表示開放狀態
        elif status_filter == "closed":
            params['status_id'] = 'c'  # Redmine API 使用 'c' 表示關閉狀態
        
        # 取得議題列表
        issues = client.list_issues(**params)
        
        if not issues:
            return f"沒有找到指派給 {user_name.strip()} 的{status_filter}議題"
        
        # 格式化結果
        result = f"""指派給 {user_name.strip()} 的議題:
狀態篩選: {status_filter}
找到 {len(issues)} 個議題:

{"ID":<8} {"標題":<35} {"專案":<15} {"狀態":<12} {"更新時間":<10}
{"-"*8} {"-"*35} {"-"*15} {"-"*12} {"-"*10}"""

        for issue in issues:
            title = issue.subject[:32] + "..." if len(issue.subject) > 35 else issue.subject
            project_name = issue.project.get('name', 'N/A')[:13]
            status = issue.status.get('name', 'N/A')[:10]
            updated = issue.updated_on[:10] if issue.updated_on else 'N/A'
            
            result += f"\n{issue.id:<8} {title:<35} {project_name:<15} {status:<12} {updated:<10}"
        
        return result
        
    except RedmineAPIError as e:
        return f"取得我的議題失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def close_issue(issue_id: int, notes: str = "", done_ratio: int = 100) -> str:
    """
    關閉議題（設定為已完成狀態）
    
    Args:
        issue_id: 議題 ID
        notes: 關閉備註（可選）
        done_ratio: 完成百分比（預設 100%）
    
    Returns:
        關閉結果訊息
    """
    try:
        client = get_client()
        
        # 取得可用狀態列表，尋找關閉狀態
        statuses = client.get_issue_statuses()
        closed_status_id = None
        
        for status in statuses:
            if status.get('is_closed', False):
                closed_status_id = status['id']
                break
        
        if closed_status_id is None:
            return "錯誤: 找不到可用的關閉狀態"
        
        # 準備更新資料
        update_data = {
            'status_id': closed_status_id,
            'done_ratio': min(max(done_ratio, 0), 100)
        }
        
        if notes.strip():
            update_data['notes'] = notes.strip()
        
        # 執行更新
        client.update_issue(issue_id, **update_data)
        
        # 取得更新後的議題資訊
        updated_issue = client.get_issue(issue_id)
        
        result = f"""議題關閉成功!

議題: #{issue_id} - {updated_issue.subject}
狀態: {updated_issue.status.get('name', 'N/A')}
完成度: {updated_issue.done_ratio}%"""

        if notes.strip():
            result += f"\n關閉備註: {notes}"

        return result
        
    except RedmineAPIError as e:
        return f"關閉議題失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def search_users(query: str, limit: int = 10) -> str:
    """
    搜尋用戶（依姓名或登入名）
    
    Args:
        query: 搜尋關鍵字（姓名或登入名）
        limit: 最大回傳數量 (預設 10，最大 50)
    
    Returns:
        符合搜尋條件的用戶列表
    """
    try:
        if not query.strip():
            return "請提供搜尋關鍵字"
        
        client = get_client()
        limit = min(max(limit, 1), 50)
        
        users = client.search_users(query, limit)
        
        if not users:
            return f"沒有找到匹配「{query}」的用戶"
        
        result = f"搜尋關鍵字: '{query}'\n找到 {len(users)} 個相關用戶:\n\n"
        result += f"{'ID':<5} {'登入名':<15} {'姓名':<20} {'狀態':<8}\n"
        result += f"{'-'*5} {'-'*15} {'-'*20} {'-'*8}\n"
        
        for user in users:
            full_name = f"{user.firstname} {user.lastname}".strip()
            if not full_name:
                full_name = user.login
            status_text = "啟用" if user.status == 1 else "停用"
            result += f"{user.id:<5} {user.login:<15} {full_name:<20} {status_text:<8}\n"
        
        return result
        
    except RedmineAPIError as e:
        return f"搜尋用戶失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def list_users(limit: int = 20, status_filter: str = "active") -> str:
    """
    列出所有用戶
    
    Args:
        limit: 最大回傳數量 (預設 20，最大 100)
        status_filter: 狀態篩選 ("active", "locked", "all")
    
    Returns:
        用戶列表，以表格格式呈現
    """
    try:
        client = get_client()
        limit = min(max(limit, 1), 100)
        
        # 轉換狀態篩選
        status = None
        if status_filter == "active":
            status = 1
        elif status_filter == "locked":
            status = 3
        
        users = client.list_users(limit=limit, status=status)
        
        if not users:
            return "沒有找到用戶"
        
        result = f"找到 {len(users)} 個用戶:\n\n"
        result += f"{'ID':<5} {'登入名':<15} {'姓名':<20} {'Email':<25} {'狀態':<8}\n"
        result += f"{'-'*5} {'-'*15} {'-'*20} {'-'*25} {'-'*8}\n"
        
        for user in users:
            full_name = f"{user.firstname} {user.lastname}".strip()
            if not full_name:
                full_name = user.login
            status_text = "啟用" if user.status == 1 else "停用"
            email = user.mail[:22] + "..." if len(user.mail) > 25 else user.mail
            result += f"{user.id:<5} {user.login:<15} {full_name:<20} {email:<25} {status_text:<8}\n"
        
        return result
        
    except RedmineAPIError as e:
        return f"取得用戶列表失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def get_user(user_id: int) -> str:
    """
    取得特定用戶的詳細資訊
    
    Args:
        user_id: 用戶 ID
        
    Returns:
        用戶的詳細資訊，以易讀格式呈現
    """
    try:
        client = get_client()
        user_data = client.get_user(user_id)
        
        # 格式化用戶資訊
        result = f"用戶 #{user_id}: {user_data.get('firstname', '')} {user_data.get('lastname', '')}\n\n"
        result += "基本資訊:\n"
        result += f"- 登入名: {user_data.get('login', 'N/A')}\n"
        result += f"- Email: {user_data.get('mail', 'N/A')}\n"
        result += f"- 狀態: {'啟用' if user_data.get('status', 1) == 1 else '停用'}\n"
        result += f"- 建立時間: {user_data.get('created_on', 'N/A')}\n"
        
        if user_data.get('last_login_on'):
            result += f"- 最後登入: {user_data.get('last_login_on')}\n"
        
        # 群組資訊
        if user_data.get('groups'):
            result += "\n群組:\n"
            for group in user_data['groups']:
                result += f"- {group.get('name', 'N/A')}\n"
        
        # 自訂欄位
        if user_data.get('custom_fields'):
            result += "\n自訂欄位:\n"
            for field in user_data['custom_fields']:
                if field.get('value'):
                    result += f"- {field.get('name', 'N/A')}: {field.get('value', 'N/A')}\n"
        
        return result
        
    except RedmineAPIError as e:
        return f"取得用戶資訊失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


@mcp.tool()
def refresh_cache() -> str:
    """
    手動刷新列舉值和用戶快取
    
    Returns:
        刷新結果訊息
    """
    try:
        client = get_client()
        client.refresh_cache()
        
        # 取得快取資訊
        cache = client._load_enum_cache()
        domain = cache.get('domain', 'N/A')
        cache_time = cache.get('cache_time', 0)
        
        if cache_time > 0:
            cache_datetime = datetime.fromtimestamp(cache_time).strftime('%Y-%m-%d %H:%M:%S')
        else:
            cache_datetime = 'N/A'
        
        result = f"""快取刷新成功!

Domain: {domain}
快取時間: {cache_datetime}

快取內容統計:
- 優先權: {len(cache.get('priorities', {}))} 個
- 狀態: {len(cache.get('statuses', {}))} 個  
- 追蹤器: {len(cache.get('trackers', {}))} 個
- 用戶（姓名）: {len(cache.get('users_by_name', {}))} 個
- 用戶（登入名）: {len(cache.get('users_by_login', {}))} 個

快取位置: {client._cache_file}"""
        
        return result
        
    except RedmineAPIError as e:
        return f"刷新快取失敗: {str(e)}"
    except Exception as e:
        return f"系統錯誤: {str(e)}"


def main():
    """MCP 服務器主入口點"""
    # 透過 stdio 運行服務器
    mcp.run('stdio')


if __name__ == "__main__":
    main()