import { query, queryOne, execute } from "./db";
import type {
  SupportRequest,
  SupportMessage,
  DashboardStats,
  RequestStatus,
  AdminUser,
} from "@shared/schema";

export interface IStorage {
  getRequests(): Promise<SupportRequest[]>;
  getRequestById(id: number): Promise<SupportRequest | null>;
  getRequestMessages(requestId: number): Promise<SupportMessage[]>;
  getUserRequests(userId: number): Promise<SupportRequest[]>;
  updateRequestStatus(id: number, status: RequestStatus): Promise<void>;
  addMessage(requestId: number, message: string, isAdmin: boolean): Promise<void>;
  getStats(): Promise<DashboardStats>;
  getAdmin(username: string): Promise<AdminUser | null>;
}

export class MySQLStorage implements IStorage {
  async getRequests(): Promise<SupportRequest[]> {
    try {
      const rows = await query<any>(`
        SELECT 
          id,
          user_id,
          user_first_name,
          user_username,
          request,
          media,
          tookBy,
          solved_by,
          created_timestamp,
          solved_timestamp
        FROM requests
        ORDER BY created_timestamp DESC
      `);

      return rows.map((row) => this.mapRequest(row));
    } catch (error) {
      console.error("Error fetching requests:", error);
      return [];
    }
  }

  async getRequestById(id: number): Promise<SupportRequest | null> {
    try {
      const row = await queryOne<any>(`
        SELECT 
          id,
          user_id,
          user_first_name,
          user_username,
          request,
          media,
          tookBy,
          solved_by,
          created_timestamp,
          solved_timestamp
        FROM requests
        WHERE id = ?
      `, [id]);

      if (!row) return null;
      return this.mapRequest(row);
    } catch (error) {
      console.error("Error fetching request:", error);
      return null;
    }
  }

  async getRequestMessages(requestId: number): Promise<SupportMessage[]> {
    try {
      const request = await this.getRequestById(requestId);
      if (!request) return [];

      const rows = await query<any>(`
        SELECT 
          id,
          chat_id,
          first_name,
          last_name,
          username,
          message_id,
          timestamp_of_message,
          sent_to,
          status
        FROM messages
        WHERE chat_id = ?
        ORDER BY timestamp_of_message ASC
      `, [request.odID]);

      return rows.map((row) => ({
        id: row.id,
        odID: parseInt(row.chat_id) || 0,
        odFirstName: row.first_name || "",
        odLastName: row.last_name || "",
        odUsername: row.username || "",
        text: `Сообщение #${row.message_id}`,
        isAdmin: !!row.sent_to,
        timestamp: parseInt(row.timestamp_of_message) || 0,
        requestId: requestId,
      }));
    } catch (error) {
      console.error("Error fetching messages:", error);
      return [];
    }
  }

  async getUserRequests(userId: number): Promise<SupportRequest[]> {
    try {
      const rows = await query<any>(`
        SELECT 
          id,
          user_id,
          user_first_name,
          user_username,
          request,
          media,
          tookBy,
          solved_by,
          created_timestamp,
          solved_timestamp
        FROM requests
        WHERE user_id = ?
        ORDER BY created_timestamp DESC
      `, [String(userId)]);

      return rows.map((row) => this.mapRequest(row));
    } catch (error) {
      console.error("Error fetching user requests:", error);
      return [];
    }
  }

  async updateRequestStatus(id: number, status: RequestStatus): Promise<void> {
    try {
      const now = Math.floor(Date.now() / 1000);
      
      if (status === "in_progress") {
        await execute(`
          UPDATE requests
          SET tookBy = 'admin', tookTimestamp = ?
          WHERE id = ?
        `, [String(now), id]);
      } else if (status === "resolved") {
        await execute(`
          UPDATE requests
          SET solved_by = 'admin', solved_timestamp = ?
          WHERE id = ?
        `, [String(now), id]);
      } else if (status === "new") {
        await execute(`
          UPDATE requests
          SET tookBy = NULL, tookTimestamp = NULL, solved_by = NULL, solved_timestamp = NULL
          WHERE id = ?
        `, [id]);
      }
    } catch (error) {
      console.error("Error updating request status:", error);
      throw error;
    }
  }

  async addMessage(requestId: number, message: string, isAdmin: boolean): Promise<void> {
    try {
      const request = await this.getRequestById(requestId);
      if (!request) throw new Error("Request not found");

      if (isAdmin) {
        await execute(`
          UPDATE requests
          SET response = ?
          WHERE id = ?
        `, [message, requestId]);
      }
    } catch (error) {
      console.error("Error adding message:", error);
      throw error;
    }
  }

  async getStats(): Promise<DashboardStats> {
    try {
      const totalResult = await queryOne<{ count: number }>(`
        SELECT COUNT(*) as count FROM requests
      `);

      const newResult = await queryOne<{ count: number }>(`
        SELECT COUNT(*) as count FROM requests 
        WHERE (tookBy IS NULL OR tookBy = '') AND (solved_by IS NULL OR solved_by = '')
      `);

      const inProgressResult = await queryOne<{ count: number }>(`
        SELECT COUNT(*) as count FROM requests 
        WHERE tookBy IS NOT NULL AND tookBy != '' AND (solved_by IS NULL OR solved_by = '')
      `);

      const resolvedResult = await queryOne<{ count: number }>(`
        SELECT COUNT(*) as count FROM requests 
        WHERE solved_by IS NOT NULL AND solved_by != ''
      `);

      const usersResult = await queryOne<{ count: number }>(`
        SELECT COUNT(DISTINCT user_id) as count FROM requests
      `);

      return {
        totalRequests: totalResult?.count || 0,
        newRequests: newResult?.count || 0,
        inProgressRequests: inProgressResult?.count || 0,
        resolvedRequests: resolvedResult?.count || 0,
        activeUsers: usersResult?.count || 0,
      };
    } catch (error) {
      console.error("Error fetching stats:", error);
      return {
        totalRequests: 0,
        newRequests: 0,
        inProgressRequests: 0,
        resolvedRequests: 0,
        activeUsers: 0,
      };
    }
  }

  async getAdmin(username: string): Promise<AdminUser | null> {
    try {
      const row = await queryOne<any>(`
        SELECT id, chat_id, username
        FROM admins
        WHERE username = ? AND status = 1
      `, [username]);

      if (!row) return null;

      return {
        id: String(row.id),
        username: row.username,
      };
    } catch (error) {
      console.error("Error fetching admin:", error);
      return null;
    }
  }

  private mapRequest(row: any): SupportRequest {
    let status: RequestStatus = "new";
    if (row.solved_by && row.solved_by !== "") {
      status = "resolved";
    } else if (row.tookBy && row.tookBy !== "") {
      status = "in_progress";
    }

    return {
      id: row.id,
      odID: parseInt(row.user_id) || 0,
      odFirstName: row.user_first_name || "",
      odLastName: "",
      odUsername: row.user_username || "",
      text: row.request || "",
      media: row.media || null,
      status,
      timestamp: parseInt(row.created_timestamp) || 0,
      takenBy: row.tookBy ? 1 : null,
    };
  }
}

export class MemStorage implements IStorage {
  private requests: Map<number, SupportRequest> = new Map();
  private messages: Map<number, SupportMessage[]> = new Map();
  private nextId = 1;

  constructor() {
    const now = Math.floor(Date.now() / 1000);
    const sampleRequests: SupportRequest[] = [
      {
        id: 1,
        odID: 123456789,
        odFirstName: "Иван",
        odLastName: "Петров",
        odUsername: "ivan_petrov",
        text: "Не могу найти фильм 'Интерстеллар'. Помогите, пожалуйста!",
        media: null,
        status: "new",
        timestamp: now - 3600,
        takenBy: null,
      },
      {
        id: 2,
        odID: 987654321,
        odFirstName: "Мария",
        odLastName: "Сидорова",
        odUsername: "maria_sid",
        text: "Бот не отвечает на команду /start. Что делать?",
        media: null,
        status: "in_progress",
        timestamp: now - 7200,
        takenBy: 1,
      },
      {
        id: 3,
        odID: 555666777,
        odFirstName: "Алексей",
        odLastName: "Козлов",
        odUsername: "alexey_k",
        text: "Хочу предложить добавить новый функционал - рейтинг фильмов",
        media: null,
        status: "resolved",
        timestamp: now - 86400,
        takenBy: 1,
      },
    ];

    for (const req of sampleRequests) {
      this.requests.set(req.id, req);
      this.messages.set(req.id, [
        {
          id: 1,
          odID: req.odID,
          odFirstName: req.odFirstName,
          odLastName: req.odLastName,
          odUsername: req.odUsername,
          text: req.text,
          isAdmin: false,
          timestamp: req.timestamp,
          requestId: req.id,
        },
      ]);
    }
    this.nextId = 4;
  }

  async getRequests(): Promise<SupportRequest[]> {
    return Array.from(this.requests.values()).sort((a, b) => b.timestamp - a.timestamp);
  }

  async getRequestById(id: number): Promise<SupportRequest | null> {
    return this.requests.get(id) || null;
  }

  async getRequestMessages(requestId: number): Promise<SupportMessage[]> {
    return this.messages.get(requestId) || [];
  }

  async getUserRequests(userId: number): Promise<SupportRequest[]> {
    return Array.from(this.requests.values())
      .filter((r) => r.odID === userId)
      .sort((a, b) => b.timestamp - a.timestamp);
  }

  async updateRequestStatus(id: number, status: RequestStatus): Promise<void> {
    const request = this.requests.get(id);
    if (request) {
      request.status = status;
    }
  }

  async addMessage(requestId: number, message: string, isAdmin: boolean): Promise<void> {
    const request = this.requests.get(requestId);
    if (!request) throw new Error("Request not found");

    const msgs = this.messages.get(requestId) || [];
    msgs.push({
      id: msgs.length + 1,
      odID: request.odID,
      odFirstName: request.odFirstName,
      odLastName: request.odLastName,
      odUsername: request.odUsername,
      text: message,
      isAdmin,
      timestamp: Math.floor(Date.now() / 1000),
      requestId,
    });
    this.messages.set(requestId, msgs);
  }

  async getStats(): Promise<DashboardStats> {
    const requests = Array.from(this.requests.values());
    const userIds = new Set(requests.map((r) => r.odID));

    return {
      totalRequests: requests.length,
      newRequests: requests.filter((r) => r.status === "new").length,
      inProgressRequests: requests.filter((r) => r.status === "in_progress").length,
      resolvedRequests: requests.filter((r) => r.status === "resolved").length,
      activeUsers: userIds.size,
    };
  }

  async getAdmin(username: string): Promise<AdminUser | null> {
    if (username === "admin") {
      return { id: "1", username: "admin" };
    }
    return null;
  }
}

function hasMySQL(): boolean {
  return !!(
    process.env.MYSQL_HOST &&
    process.env.MYSQL_USER &&
    process.env.MYSQL_PASSWORD &&
    process.env.MYSQL_DATABASE
  );
}

export const storage: IStorage = hasMySQL() ? new MySQLStorage() : new MemStorage();
