/* eslint-disable @typescript-eslint/no-explicit-any */
import axios from 'axios';
import { IntegrationAccount } from '@redplanethq/sol-sdk';

interface LinearActivityCreateParams {
  url: string;
  title: string;
  sourceId: string;
  sourceURL: string;
  integrationAccountId: string;
}

interface LinearSettings {
  lastIssuesSync?: string;
  lastCommentsSync?: string;
  lastUserActionsSync?: string;
}

// Event types to track for user activities
enum LinearEventType {
  ISSUE_CREATED = 'issue_created',
  ISSUE_UPDATED = 'issue_updated',
  ISSUE_COMMENTED = 'issue_commented',
  ISSUE_ASSIGNED = 'issue_assigned',
  ISSUE_STATUS_CHANGED = 'issue_status_changed',
  ISSUE_COMPLETED = 'issue_completed',
  ISSUE_REOPENED = 'issue_reopened',
  USER_MENTIONED = 'user_mentioned',
  REACTION_ADDED = 'reaction_added',
  ISSUE_SUBSCRIBED = 'issue_subscribed',
  ISSUE_PRIORITY_CHANGED = 'issue_priority_changed',
  PROJECT_UPDATED = 'project_updated',
  CYCLE_UPDATED = 'cycle_updated',
}

// GraphQL fragments for reuse
const USER_FRAGMENT = `
  fragment UserFields on User {
    id
    name
    displayName
  }
`;

const ISSUE_FRAGMENT = `
  fragment IssueFields on Issue {
    id
    identifier
    title
    description
    url
    createdAt
    updatedAt
    archivedAt
    state {
      id
      name
      type
    }
    team {
      id
      name
    }
    assignee {
      ...UserFields
    }
    creator {
      ...UserFields
    }
    subscribers {
      nodes {
        ...UserFields
      }
    }
    priority
  }
  ${USER_FRAGMENT}
`;

const COMMENT_FRAGMENT = `
  fragment CommentFields on Comment {
    id
    body
    createdAt
    updatedAt
    user {
      ...UserFields
    }
    issue {
      ...IssueFields
    }
  }
  ${USER_FRAGMENT}
  ${ISSUE_FRAGMENT}
`;

/**
 * Creates an activity in the system based on Linear data
 */
async function createActivity(params: LinearActivityCreateParams) {
  try {
    // This would call the Sol SDK to create an activity
    console.log(`Creating activity: ${params.title}`);
    // Would be implemented via Sol SDK similar to GitHub integration
  } catch (error) {
    console.error('Error creating activity:', error);
  }
}

/**
 * Fetches user information from Linear
 */
async function fetchUserInfo(accessToken: string) {
  try {
    const query = `
      query {
        viewer {
          id
          name
          email
        }
      }
    `;

    const response = await axios.post(
      'https://api.linear.app/graphql',
      { query },
      {
        headers: {
          'Content-Type': 'application/json',
          Authorization: `Bearer ${accessToken}`,
        },
      },
    );

    return response.data.data.viewer;
  } catch (error) {
    console.error('Error fetching user info:', error);
    throw error;
  }
}

/**
 * Fetches recent issues relevant to the user (created, assigned, or subscribed)
 */
async function fetchRecentIssues(accessToken: string, lastSyncTime: string) {
  try {
    const query = `
      query RecentIssues($lastSyncTime: DateTime) {
        issues(
          filter: {
            updatedAt: { gt: $lastSyncTime }
          },
          first: 50,
          orderBy: updatedAt
        ) {
          nodes {
            ...IssueFields
            history {
              nodes {
                id
                createdAt
                updatedAt
                fromStateId
                toStateId
                fromAssigneeId
                toAssigneeId
                fromPriority
                toPriority
              }
            }
          }
          pageInfo {
            hasNextPage
            endCursor
          }
        }
      }
      ${ISSUE_FRAGMENT}
    `;

    const response = await axios.post(
      'https://api.linear.app/graphql',
      {
        query,
        variables: {
          lastSyncTime,
        },
      },
      {
        headers: {
          'Content-Type': 'application/json',
          Authorization: `Bearer ${accessToken}`,
        },
      },
    );

    return response.data.data.issues;
  } catch (error) {
    console.error('Error fetching recent issues:', error);
    throw error;
  }
}

/**
 * Fetches recent comments on issues relevant to the user
 */
async function fetchRecentComments(accessToken: string, lastSyncTime: string) {
  try {
    const query = `
      query RecentComments($lastSyncTime: DateTime) {
        comments(
          filter: {
            updatedAt: { gt: $lastSyncTime }
          },
          first: 50,
          orderBy: updatedAt
        ) {
          nodes {
            ...CommentFields
          }
          pageInfo {
            hasNextPage
            endCursor
          }
        }
      }
      ${COMMENT_FRAGMENT}
    `;

    const response = await axios.post(
      'https://api.linear.app/graphql',
      {
        query,
        variables: {
          lastSyncTime,
        },
      },
      {
        headers: {
          'Content-Type': 'application/json',
          Authorization: `Bearer ${accessToken}`,
        },
      },
    );

    return response.data.data.comments;
  } catch (error) {
    console.error('Error fetching recent comments:', error);
    throw error;
  }
}

/**
 * Process issue activities and create appropriate activity records
 */
async function processIssueActivities(
  issues: any[],
  userId: string,
  integrationAccount: IntegrationAccount,
  isCreator: boolean = false,
) {
  const activities = [];

  for (const issue of issues) {
    try {
      // Skip issues that don't involve the user
      const isAssignee = issue.assignee?.id === userId;
      const isCreatedByUser = issue.creator?.id === userId;

      // Check if user is subscribed to the issue
      const isSubscribed =
        issue.subscribers?.nodes?.some((subscriber: any) => subscriber.id === userId) || false;

      if (!isAssignee && !isCreatedByUser && !isCreator && !isSubscribed) {
        continue;
      }

      // Process new issues created by the user
      if (isCreatedByUser) {
        activities.push({
          url: `https://api.linear.app/issue/${issue.id}`,
          title: `You created issue ${issue.identifier}: ${issue.title}`,
          sourceId: `linear-issue-created-${issue.id}`,
          sourceURL: issue.url,
          integrationAccountId: integrationAccount.id,
        });
      }

      // Process issues assigned to the user (if not created by them)
      if (isAssignee && !isCreatedByUser) {
        activities.push({
          url: `https://api.linear.app/issue/${issue.id}`,
          title: `${issue.creator?.name || 'Someone'} assigned you issue ${issue.identifier}: ${issue.title}`,
          sourceId: `linear-issue-assigned-${issue.id}`,
          sourceURL: issue.url,
          integrationAccountId: integrationAccount.id,
        });
      }

      // Process issues where the user is subscribed (if not creator or assignee)
      if (isSubscribed && !isCreatedByUser && !isAssignee) {
        activities.push({
          url: `https://api.linear.app/issue/${issue.id}`,
          title: `Update on issue ${issue.identifier} you're subscribed to: ${issue.title}`,
          sourceId: `linear-issue-subscribed-${issue.id}`,
          sourceURL: issue.url,
          integrationAccountId: integrationAccount.id,
        });
      }

      // Process status changes
      if (issue.history && issue.history.nodes) {
        for (const historyItem of issue.history.nodes) {
          if (historyItem.toStateId && historyItem.fromStateId !== historyItem.toStateId) {
            // Skip if not relevant to the user
            if (!isAssignee && !isCreatedByUser && !isSubscribed) {
              continue;
            }

            const stateType = issue.state?.type;
            let eventType = LinearEventType.ISSUE_STATUS_CHANGED;
            let statusText = `moved to ${issue.state?.name || 'a new status'}`;

            // Special handling for completion and reopening
            if (stateType === 'completed') {
              eventType = LinearEventType.ISSUE_COMPLETED;
              statusText = 'marked as completed';
            } else if (stateType === 'canceled') {
              statusText = 'canceled';
            } else if (historyItem.fromStateId && !historyItem.toStateId) {
              eventType = LinearEventType.ISSUE_REOPENED;
              statusText = 'reopened';
            }

            let title;
            if (isCreatedByUser || isAssignee) {
              title = `You ${statusText} issue ${issue.identifier}: ${issue.title}`;
            } else if (isSubscribed) {
              title = `Issue ${issue.identifier} you're subscribed to was ${statusText}: ${issue.title}`;
            } else {
              title = `${issue.assignee?.name || 'Someone'} ${statusText} issue ${issue.identifier}: ${issue.title}`;
            }

            activities.push({
              url: `https://api.linear.app/issue/${issue.id}`,
              title,
              sourceId: `linear-${eventType}-${issue.id}-${historyItem.id}`,
              sourceURL: issue.url,
              integrationAccountId: integrationAccount.id,
            });
          }

          // Process priority changes
          if (historyItem.toPriority && historyItem.fromPriority !== historyItem.toPriority) {
            // Skip if not relevant to the user
            if (!isAssignee && !isCreatedByUser && !isSubscribed) {
              continue;
            }

            const priorityMap: Record<number, string> = {
              0: 'No priority',
              1: 'Urgent',
              2: 'High',
              3: 'Medium',
              4: 'Low',
            };

            const newPriority = priorityMap[historyItem.toPriority] || 'a new priority';

            let title;
            if (isCreatedByUser) {
              title = `You changed priority of issue ${issue.identifier} to ${newPriority}`;
            } else if (isAssignee) {
              title = `${issue.creator?.name || 'Someone'} changed priority of your assigned issue ${issue.identifier} to ${newPriority}`;
            } else if (isSubscribed) {
              title = `Priority of issue ${issue.identifier} you're subscribed to changed to ${newPriority}`;
            } else {
              title = `${issue.creator?.name || 'Someone'} changed priority of issue ${issue.identifier} to ${newPriority}`;
            }

            activities.push({
              url: `https://api.linear.app/issue/${issue.id}`,
              title,
              sourceId: `linear-issue-priority-${issue.id}-${historyItem.id}`,
              sourceURL: issue.url,
              integrationAccountId: integrationAccount.id,
            });
          }

          // Process assignment changes
          if (historyItem.toAssigneeId && historyItem.fromAssigneeId !== historyItem.toAssigneeId) {
            // Only relevant if user is newly assigned or is the creator
            if (historyItem.toAssigneeId !== userId && !isCreatedByUser) {
              continue;
            }

            const title =
              historyItem.toAssigneeId === userId
                ? `You were assigned issue ${issue.identifier}: ${issue.title}`
                : `You assigned issue ${issue.identifier} to ${issue.assignee?.name || 'someone'}`;

            activities.push({
              url: `https://api.linear.app/issue/${issue.id}`,
              title,
              sourceId: `linear-issue-reassigned-${issue.id}-${historyItem.id}`,
              sourceURL: issue.url,
              integrationAccountId: integrationAccount.id,
            });
          }
        }
      }
    } catch (error) {
      console.error(`Error processing issue ${issue.id}:`, error);
    }
  }

  // Create activities in the system
  for (const activity of activities) {
    await createActivity(activity);
  }

  return activities.length;
}

/**
 * Process comment activities and create appropriate activity records
 */
async function processCommentActivities(
  comments: any[],
  userId: string,
  integrationAccount: IntegrationAccount,
) {
  const activities = [];

  for (const comment of comments) {
    try {
      const isCommenter = comment.user?.id === userId;
      const isIssueCreator = comment.issue?.creator?.id === userId;
      const isAssignee = comment.issue?.assignee?.id === userId;

      // Check if user is subscribed to the issue
      const isSubscribed =
        comment.issue?.subscribers?.nodes?.some((subscriber: any) => subscriber.id === userId) ||
        false;

      // Skip if not relevant to user
      if (!isCommenter && !isIssueCreator && !isAssignee && !isSubscribed) {
        // TODO: Check for mentions in the comment body
        continue;
      }

      let title;
      let sourceId;

      if (isCommenter) {
        // Comment created by the user
        title = `You commented on issue ${comment.issue.identifier}: ${truncateText(comment.body, 100)}`;
        sourceId = `linear-comment-created-${comment.id}`;
      } else if (isAssignee || isIssueCreator || isSubscribed) {
        // Comment on issue where user is assignee, creator, or subscriber
        let relation = 'an issue';
        if (isAssignee) {
          relation = 'your assigned issue';
        } else if (isIssueCreator) {
          relation = 'your issue';
        } else if (isSubscribed) {
          relation = "an issue you're subscribed to";
        }
        title = `${comment.user?.name || 'Someone'} commented on ${relation} ${comment.issue.identifier}: ${truncateText(comment.body, 100)}`;
        sourceId = `linear-comment-received-${comment.id}`;
      }

      if (title && sourceId) {
        activities.push({
          url: `https://api.linear.app/comment/${comment.id}`,
          title,
          sourceId,
          sourceURL: `${comment.issue.url}#comment-${comment.id}`,
          integrationAccountId: integrationAccount.id,
        });
      }
    } catch (error) {
      console.error(`Error processing comment ${comment.id}:`, error);
    }
  }

  // Create activities in the system
  for (const activity of activities) {
    await createActivity(activity);
  }

  return activities.length;
}

/**
 * Helper function to truncate text with ellipsis
 */
function truncateText(text: string, maxLength: number): string {
  if (!text) return '';
  return text.length > maxLength ? text.substring(0, maxLength) + '...' : text;
}

/**
 * Helper function to get default sync time (24 hours ago)
 */
function getDefaultSyncTime(): string {
  const yesterday = new Date();
  yesterday.setDate(yesterday.getDate() - 1);
  return yesterday.toISOString();
}

/**
 * Main function to handle scheduled sync for Linear integration
 */
export async function handleSchedule(integrationAccount: IntegrationAccount) {
  try {
    const integrationConfiguration = integrationAccount.integrationConfiguration as any;

    // Check if we have a valid access token
    if (!integrationConfiguration?.accessToken) {
      console.error('No access token found for Linear integration');
      return { message: 'No access token found' };
    }

    // Get settings or initialize if not present
    const settings = (integrationAccount.settings || {}) as LinearSettings;

    // Default to 24 hours ago if no last sync times
    const lastIssuesSync = settings.lastIssuesSync || getDefaultSyncTime();
    const lastCommentsSync = settings.lastCommentsSync || getDefaultSyncTime();

    // Fetch user info to identify activities relevant to them
    const user = await fetchUserInfo(integrationConfiguration.accessToken);

    if (!user || !user.id) {
      console.error('Failed to fetch user info from Linear');
      return { message: 'Failed to fetch user info' };
    }

    // Process all issue activities (created, assigned, updated, etc.)
    let issueCount = 0;
    try {
      const issues = await fetchRecentIssues(integrationConfiguration.accessToken, lastIssuesSync);
      if (issues && issues.nodes) {
        issueCount = await processIssueActivities(issues.nodes, user.id, integrationAccount);
      }
    } catch (error) {
      console.error('Error processing issues:', error);
    }

    // Process all comment activities
    let commentCount = 0;
    try {
      const comments = await fetchRecentComments(
        integrationConfiguration.accessToken,
        lastCommentsSync,
      );
      if (comments && comments.nodes) {
        commentCount = await processCommentActivities(comments.nodes, user.id, integrationAccount);
      }
    } catch (error) {
      console.error('Error processing comments:', error);
    }

    // TODO: Implement additional activity types:
    // - Reaction tracking
    // - PR/Merge request tracking (if supported by Linear)
    // - Project and cycle updates
    // - Team updates and notifications
    // - Mention detection in descriptions and comments

    // Update last sync times
    const newSyncTime = new Date().toISOString();

    // Save new settings
    integrationAccount.settings = {
      ...settings,
      lastIssuesSync: newSyncTime,
      lastCommentsSync: newSyncTime,
    };

    return {
      message: `Synced ${issueCount} issues and ${commentCount} comments from Linear`,
    };
  } catch (error) {
    console.error('Error in Linear scheduled sync:', error);
    return {
      message: `Error syncing Linear activities: ${error instanceof Error ? error.message : 'Unknown error'}`,
    };
  }
}

/**
 * The main handler for the scheduled sync event
 */
export async function scheduleHandler(integrationAccount: IntegrationAccount) {
  return handleSchedule(integrationAccount);
}
